Hello everyone, I’m Xiao CAI. A man who wants to be a man who talks architecture! If you also want to be the person I want to be, or point a concern to do a companion, let small dishes no longer lonely!

This article focuses on the SPI mechanism

Refer to it if necessary

If it is helpful, do not forget the Sunday

Wechat public account has been opened, vegetable farmers said, do not pay attention to the students remember to pay attention to oh!

In our last article, we talked about the use of Agent in Java. Many friends feel that this way is relatively one-sided, and it is not commonly used in normal development (almost useless). In fact, not commonly used is linked to the project, the project is not commonly used does not mean that the method mechanism is not commonly used, so a lot of times we can not learn from the perspective of the project, think that the project is useless can not learn, grow with the project often can not grow ~!

Java Advanced Usage, write a proxy to invade you?

So in this article we will continue to talk about another topic in Java, namely SPI mechanism, which still sounds strange at first. Don’t give up! Look down and you’ll see it all the time in development!

A, SPI

This article is problem-oriented and uses questions to drive learning. The small dish first throws out several questions, which will be explained and expanded below

  • What is SPI?
  • What’s the difference between SPI and API?
  • Is SPI used in daily life?

1. What is SPI

SPI stands for three words: Service Provider Interface. It is a set of interfaces provided by Java that can be implemented or extended by third parties and can be used to enable framework extensions and replace components. The idea is to find service implementations for these extended apis.

The Java SPI is a service discovery mechanism built into the JDK. It is often used to create applications with extensible and replaceable components, which is the key to modularization and plug-in in Java.

There are two concepts mentioned here, modularity and plug-in. Modularity is easy to understand, which is to divide a project into multiple modules, which may be interdependent (i.e., by means of Maven). For those who use microservice development, it does not matter if they do not use microservice development. The Repository layer also extracts each domain as a module, rather than as a directory

Class loading mechanism

We’ve already covered some of the basics of SPI, but we’re not going to dive into SPI directly here. Before we dive into SPI, let’s take a look at the classloading mechanism in Java. Classloading may not be something you really care about in development, but it’s ubiquitous, and it’s a hot topic in interviews.

In the JVM, classloaders default to the parent delegate principle, The default class loaders include Bootstarp ClassLoader, Extension ClassLoader, and System ClassLoader. Custom class loaders can be implemented by inheriting java.lang.classloader

The scope of each class loader is as follows:

  • Bootstrap ClassLoader: loads the classes in the Rt. jar package of the JDK. Bootstrap ClassLoader is the parent class of all classes loaded
  • Extension ClassLoader loads classes from the directory specified by the jre/lib/ect or java.ext.dirs system property
  • System ClassLoader: Is responsible for loading class files from the CLASspath environment variable

Class loading inheritance diagram is as follows:

1) Parental delegation model

What is the parental delegation model?

When a ClassLoader receives the task of loading a class, it will first hand it over to its parent loader to complete the task from level to level. Therefore, it will finally pass the task to the Bootstrap ClassLoader for loading. Only when the parent loader fails to complete the task, it will try to load the class itself

Why is it designed this way?

1. The principle of parent delegation can avoid the repeated loading of the same class. Each loader will delegate to its parent class loader when performing class loading tasks

2. The security of class loading can be guaranteed. No matter which loader loads this class, it is ultimately entrusted to the top loader for loading, ensuring that any loader ultimately gets the same class object

The loading process is as follows:

The downside?

A subclass loader can use classes that have already been loaded by the parent class loader, while the parent class loader cannot use classes that have been loaded by the subclass loader (similar to inheritance). Java provides a number of service provider interfaces (SPIs). It allows third parties to provide implementations of these interfaces, such as the SPI service JDBC in a database. The INTERFACES to these SPIs are provided by Java core classes, and implementors are third parties. The problem is that the provider is loaded by the Bootstrap ClassLoader, while the implementer is loaded by a third-party custom ClassLoader, and the top-level class load cannot use the classes loaded by the subclass loader

The solution

The solution to this problem is to break the parental delegation principle

It can be loaded using the ContextClassLoader

Java application context loaders use AppClassLoader by default. Classes that want to be loaded by subclass loaders in the parent class loader can use thread.currentThread ().getContextClassLoader().

For example, if we want to load resources, we can use the following methods:

// Use the thread context classloader to load resources
public static void main(String[] args) throws Exception{
    String name = "java/sql/Array.class";
    Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(name);
    while(urls.hasMoreElements()) { URL url = urls.nextElement(); System.out.println(url.toString()); }}Copy the code

3, Java SPI

With class loading behind us, let’s get back to the Java SPI. Let’s get familiar with how SPI is used

The usage process diagram is as follows:

More popularly understood, SPI is really a policy pattern implementation, based on interface programming with configuration files to read. This also fits our programming style: pluggable

The following is an example:

Project Structure:

  • ICustomSvc: Service provision Interface (SPI)
  • CustomSvcOne/CustomSvcTwoImplementor (simply implemented in a project or jar package import)
  • cbuc.life.spi.service.ICustomSvc: Configuration file

Contents of the document:

Then we launch CustomTest to view the console results

You can see that this is a method that can be loaded into our implementation class, which means that SPI functionality has been implemented

1) Implementation principle

In fact, one of the key classes you can see from SPI above is ServiceLoader. This class is in the java.util package. Let’s just click on the load() method and see how to call it

Click on the load() method first to see the following code

This block of code simply declares the use of the thread context loader. We follow up with serviceloader.load (service, CL).

This block of code is also empty, declaring that it returns a ServiceLoader object. What article does this object have? We can look at this class declaration

public final class ServiceLoader<S> implements 可迭代<S>{}
Copy the code

You can see that this object implements the Iterable interface, indicating that it has iterative methods, presumably in order to pull out all of the implementation classes we defined for SPI.

The constructor for this class is as follows

The focus is on the reload() method, which we’ll follow up on

Iterator () : iterator() : iterator() : iterator() : iterator() : iterator() : iterator() : iterator() : iterator() : iterator() : iterator() : iterator() : iterator() : iterator()) : iterator() : iterator() : iterator()) : iterator() : iterator() : iterator()

If it exists, return it. Otherwise, use the LazyIterator class to find out how to implement it. Because the class code is too long, we can use the LazyIterator class to see how to implement it. We directly intercept the key code, interested students can view the complete code:

This code will fetch file resources from the specified directory and then load the class by uploading the incoming thread context class loader. This way, our SPI implementation class can be used by projects

So far, we have broken down the use and implementation of the JAVA SPI.

4, summary

The pluggable development concept is better realized by using the Java SPI mechanism, which separates the assembly of the third-party service module from the caller’s business code, namely the concept of decoupling, so that our application can be dynamically pluggable according to the actual business needs.

Second, extension,

Spring SPI

Of course, SPI mechanism is not only implemented in JDK, we use Spring and Dubbo framework for daily development have corresponding SPI mechanism. In Spring Boot, many configurations and implementations have default implementations. If we want to modify some configurations, we only need to write the corresponding configuration in the configuration file. Then the project applies the configuration content defined by us, and this way is realized by SPI.

The differences between the Java SPI and Spring SPI

  • The loading utility class used by the JDK isServiceLoaderSpring usesSpringFactoriesLoader
  • The JDK directory is namedMeta-inf /services/ Provides the full class name of the interfaceSpring usesMETA-INF/spring-factories

Using Spring Boot, we write the class-qualified names of the classes we want to inject into the IOC container to the meta-INF/Spring.Factories file. The SpringFactoriesLoader scans the meta-INF/Spring. factories configuration files in the class-path directory of each JAR package. The properties file is then parsed to find the configuration with the specified name and returned

So SPI is everywhere in our actual development, not just Spring, for example JDBC loads database drivers, SLF4J loads logging implementations from different vendors, and Dubbo implements extensions to the framework using SPI, etc

Don’t talk, don’t be lazy, and xiao CAI do a blowing bull X do architecture of the program ape ~ point a concern to do a companion, let xiao CAI no longer lonely. See you later!

Today you work harder, tomorrow you will be able to say less words!

I am xiao CAI, a man who grows stronger with you. 💋

Wechat public account has been opened, vegetable farmers said, do not pay attention to the students remember to pay attention to oh!