Preliminary study of java SPI mechanism
1. SPI mechanism
The full name of SPI is Service Provider Interface. Most developers may not be familiar with this because it is for vendors or plug-ins. More detailed information is provided in the documentation of java.util.Service Loader. A brief summary of the idea of java spi mechanism. There are many different implementations of the abstract modules in our system, such as log module, xml parsing module, jdbc module and so on. In object-oriented design, we generally recommend that modules be programmed based on interfaces, and that implementation classes are not hard-coded between modules. Once a specific implementation class is involved in the code, it violates the pluggable principle. If you need to replace an implementation, you need to modify the code. A service discovery mechanism is needed in order to realize that modules can be assembled without being dynamically specified in the program. java spi provides a mechanism for finding service implementations for an interface. A little like the idea of IOC, which is to move the control of assembly beyond the program, this mechanism is particularly important in modular design.
2. SPI Specific Agreement
The specific convention of java spi is to create a file named after the service interface in the META-INF/services/directory of the jar package when the service provider provides an implementation of the service interface. This file is the implementation class of the service interface. When the external program assembles the module, the specific implementation class name can be found through the configuration file in the jar package META-INF/services/and loaded with instantiation to complete the injection of the module. Based on such a convention, the implementation class of the service interface can be well found without further coding. jdk provides a tool class for service implementation lookup: java.util.Service Loader
Introduction experiment:
tspi is an interface package
Alogger, an implementation package for implementing tspi for ALogger
Blogger, an implementation package for implementing tspi for BLogger
tspiTest This project is a test kit
Make these four separate projects
(1) tspi project (interface project)
A new Logger interface has four methods: debug, info, warn and error.
package com.imddy.tspi; public interface Logger { public void debug(String logger); public void info(String logger); public void warn(String logger); public void error(String logger); }
Get Logger by using the tool class LoggerFactory (spi mechanism is used here).
package com.imddy.tspi; import java.util.Iterator; import java.util.ServiceLoader; public class LoggerFactory { public LoggerFactory() { } public static Logger getLogger() { Logger logger = null; ServiceLoader<Logger> serviceLoader = ServiceLoader.load(Logger.class); Iterator<Logger> loggers = serviceLoader.iterator(); if (loggers.hasNext()) { logger = loggers.next(); } return logger; } }
This project is packaged into jar, because there is no dependency, pom.xml is basically the default content.
(2) alogger project (A implementation project)
Here is an ALogger implementation class for Logger:
package com.imddy.alogger; import com.imddy.tspi.Logger; public class ALogger implements Logger{ public ALogger() { } public void debug(String logger) { System.out.println("ALogger-->debug: " + logger); } public void info(String logger) { System.out.println("ALogger-->info: " + logger); } public void warn(String logger) { System.out.println("ALogger-->warn: " + logger); } public void error(String logger) { System.out.println("ALogger-->error: " + logger); } }
Create a META-INF/Services directory under the resource directory. Under this directory, create a new file named "com.imddy.tspi.Logger" (fully qualified name of interface) with the content of "com.imddy.alogger.ALogger" (fully qualified name of implementation class)
In pom.xml, you need to rely on the interface project, which is also packaged into a jar package.
(3) blogger Project (B Implementation Project)
Here is an implementation class of BLogger for Logger:
package com.imddy.blogger; import com.imddy.tspi.Logger; public class BLogger implements Logger{ public BLogger() { } public void debug(String logger) { System.out.println("BLogger-->debug: " + logger); } public void info(String logger) { System.out.println("BLogger-->info: " + logger); } public void warn(String logger) { System.out.println("BLogger-->warn: " + logger); } public void error(String logger) { System.out.println("BLogger-->error: " + logger); } }
Create a META-INF/Services directory under the resource directory. Under this directory, create a new file named "com.imddy.tspi.Logger" (fully qualified name of interface) with the content of "com.imddy.blogger.BLogger" (fully qualified name of implementation class)
In pom.xml, you need to rely on the interface project, which is also packaged into a jar package.
(4) tspiTest project (test project)
Dependency additions in pom.xml:
<dependency> <groupId>com.imddy</groupId> <artifactId>tspi</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <!-- <dependency> <groupId>com.imddy</groupId> <artifactId>alogger</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> --> <dependency> <groupId>com.imddy</groupId> <artifactId>blogger</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
Writing code only needs interface project dependency. Running with path class and A implementation, using A implementation and B implementation.
The test code is as follows:
package com.imddy.tspiTest; import com.imddy.tspi.Logger; import com.imddy.tspi.LoggerFactory; public class App { private static Logger logger = LoggerFactory.getLogger(); public static void main(String[] args) { logger.debug("this is use debug... "); logger.info("this is use info... "); logger.warn("this is use warn... "); logger.error("this is use error... "); } }
The operation effect is as follows: