“This is the fourth day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

1 introduction

SPI, Service Provider Interface, a Service discovery mechanism.With SPI, you can decouple the service interface from the service implementation:

  • Service providers, such as springBoot starter, provide outbound SPI interfaces. As a service provider, when you cannot impose absolute specifications, it is wise to “delegate” and let the client customize the implementation
  • The client (ordinary Springboot project) can register the implementation class to the server through local registration, easily pluggable

disadvantages

  • Cannot load on demand. Although the ServiceLoader is lazily loaded, it can only be accessed through traversal. If some of these implementation classes are time consuming and you don’t need to load them, it’s a waste of resources
  • The way to get an implementation class is not flexible and can only be obtained through iterators

Dubbo SPI implements business optimization on the above two points.

The source code

The application gets instance objects via the iterator interface, which determines whether there are instance objects in the providers object:

  • There are instances, so return
  • No, perform the class loading steps, specific class loading implementation is as follows:

LazyIterator#hasNextService reads the meta-inf /services configuration file, gets the names of all classes that can be instantiated, and completes the parsing of the SPI configuration file

LazyIterator#nextService instantiates the implementation classes read by hasNextService() and stores the instantiated objects in the providers collection

use

If an interface has three implementation classes, which implementation class does the interface choose when the system runs? You need an SPI that finds the corresponding implementation class, loads it in, and uses an instance of that implementation class, depending on the specified or default configuration.

When the following system runs, load the configuration and instantiate an object with implementation A2 to provide the service:For example, if you want to provide an implementation for an interface through a JAR package, it is in your jar packageMETA-INF/services/Jar jar jar jar jar jar jar jar jar jar jarSomeone else using this interface, and then using your JAR package, will find out at run time which implementation class to use for this interface using your JAR package specified file. This is built-in functionality in the JDK.

Can I not define it under meta-INF /services? Can I just define it somewhere else?

No! The JDK already specifies the configuration path. If you define it arbitrarily, the classloader won’t know where to load itSuppose you have A project P, and you have an interface A, and A has no implementation class in P, how do you choose an implementation class for A when the system runs? You can make your own JAR package,META-INF/services/, put A file named interface name, interface A implementation class =Com.javaedge. service. Implementation class A2. Let P depend on your jar, and when the system runs, P will run, and for interface A, it will scan the dependent JAR to see if there is anyMETA-INF/servicesFolders:

  • If yes, see if there is A file named interface A:
    • Yes, look inside the specified interface A implementation is your jar package which class

Applicable scenario

Plug-in extension

For example, if you develop an open source framework and you want someone to write their own plug-in, arrange it into your open source framework, extend the functionality.

Such as JDBC. Java defines a set of JDBC interfaces, but does not provide concrete implementation classes. Instead, it provides database implementation packages provided by different cloud vendors.

But which implementation classes of the JDBC interface will be used when the project runs?

Generally according to their use of the database driver JAR package, such as our most commonly used MySQL, itsmysql-jdbc-connector.jarHere it is:When the system runs into your JDBC interface, it will use the implementation classes provided in the jar you introduced.

case

For example, the Sharding-JDBC data encryption module supports AES and MD5 encryption. But what if the client wants to use RSA instead of the two encryption algorithms built in? Does sharding-JDBC issue a version every time an algorithm is added?

EncryptAlgorithm (EncryptAlgorithm) is a EncryptAlgorithm (EncryptAlgorithm) interface that implements SPI. The client wants to use a custom encryption algorithm, simply in the client projectMETA-INF/servicesTo define the fully qualified name file of the interface, and write the fully qualified name of the encryption implementation class in the file This shows the advantages of SPI:

  • The client (its own project) provides the server (Sharding-JDBC) interface custom implementation, but separated from the server state, only when the client provides a custom interface implementation will be loaded, other is not associated; The addition or deletion of implementation classes on the client does not affect the server
  • If the client does not want RSA algorithm, but wants to use the built-in AES algorithm, then can delete the implementation class at any time, scalability, plug-in architecture