This is the fourth day of my participation in the August More text Challenge. For details, see:August is more challenging

preface

“Spring Factoriesloader” is a tool class under spring framework. It is used to find the spring.factories under the meta-INF directory. The JDK comes with a utility class called ServiceLoader that is similar to SpringFactoriesLoader, except that this class is used to discover files in the meta-INF /services/ directory of your project. The built-in JDK mechanism is called the Service Provider Interface (SPI), which is a mechanism that Java provides to external extensions or three-party implementations.

The body of the

Use the JDK SPI

It is also easy to use, and the ServiceLoader comment also explains:

  1. The server defines an interface or abstract class
  2. Three parties or extenders do the implementation
  3. In the META-INF/services/ directory of the JAR, the third party or the extension party creates a ‘fully qualified name of the interface class’ file
  4. The class in the file is the fully qualified name of the implementation class of the interface. There can only be one line.

The following steps are customizable, where the interface and implementation are all in one package for convenience:

  1. Define an interface. The package A.B.C.D code is also simple. It is an interface in which a method is defined.

public interface TestService {
    void test(a);
}

Copy the code
  1. Implementation, package: A.B.C. D.ipl, implementation interface, custom content

public class TestServiceImpl implements TestService {
    public void test(a) {
        System.out.println("TestServiceImpl service run"); }}Copy the code
  1. In the meta-inf/services/directory to create A.B.C.D.T estService file, and then content is A.B.C.D.I MPL. TestServiceImpl

  2. call


public class ServiceLoaderTest {
    public static void main(String[] args) {
        ServiceLoader<TestService> load = ServiceLoader.load(TestService.class);
        Iterator<TestService> iterator = load.iterator();
        while(iterator.hasNext()) { TestService next = iterator.next(); next.test(); }}}Copy the code

All the implementation classes in the defined file are loaded at once and need to be iterated over.

This completes a demo that uses the JDK’s SPI mechanism.

The JDK SPI case

The first example is the JDBC DRIVER. Open the DRIVER class, which is defined in the JDK java.sql. Then introduce the MySQL package:

< the dependency > < groupId > mysql < / groupId > < artifactId > mysql connector - Java < / artifactId > < version > 8.0.25 < / version > </dependency>Copy the code

Driver file com.mysql.cj.jdbc.driver will be found in the meta-INF /services/ directory under the package. Then open this class:


public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!"); }}public Driver(a) throws SQLException {}}Copy the code

Then I open the DriverManager class, and I find a static block of code,

static { loadInitialDrivers(); println("JDBC DriverManager initialized"); } private static void loadInitialDrivers() { .... Omit... AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class); Iterator<Driver> driversIterator = loadedDrivers.iterator(); try{ while(driversIterator.hasNext()) { driversIterator.next(); } } catch(Throwable t) { } return null; }}); . Omit... for (String aDriver : driversList) { try { println("DriverManager.Initialize: loading " + aDriver); Class.forName(aDriver, true, ClassLoader.getSystemClassLoader()); } catch (Exception ex) { println("DriverManager.Initialize: load failed: " + ex); }}}Copy the code

The above code consists of two steps: 1. Load with ServiceLoader and then call class.forname ().

The last

Read the JDK SPI mechanism, the harvest is quite large. To summarize:

  1. The ServiceLoader loads all the implementation classes in the text according to the interface. If only one of the implementation classes is needed, the implementation class needs to be matched
  2. It defines a standard, which is implemented by the extender or a third party, and the service side does not have to worry about how it is implemented, achieving decoupling.
  3. The ServiceLoader and SpringFactoriesLoader functions are similar, except that one belongs to the JDK and the other belongs to the Spring framework