1. The SPI mechanism in the JDK

1.1 SPI design objectives

In object-oriented design, modules are programmed based on interfaces, and implementation classes are not hard-coded between modules. Once a specific implementation class is involved in the code, it violates the principle of pluggability, and if an implementation needs to be replaced, the code needs to be changed. In order not to write dead code during module assembly, a service discovery mechanism is needed. The Java SPI provides a mechanism for finding a service implementation for an interface. It’s a bit like the IOC idea of moving control of assembly out of the code.

The SPI mechanism is that you have an interface, and then you have a couple of implementation classes, and as you run your code you have to decide which implementation class to run, and those implementation classes are pluggable.

1.2 Specific conventions of SPI

When a service provider provides multiple implementations of an interface, a file of the same name will be created in the META-INF/services/ directory of the JAR package. The content of this file is the name of the concrete implementation class of the service interface. When the jar package meta-INF /services/ is loaded externally, the implementation class name can be obtained from the jar package meta-INF /services/ configuration file.

Here are two examples:

1, for example, load a specific SQL driver package such as mysql: Mysql-connector-java-5.1.35. jar\ meta-inf \services\java.sql.Driver is the SPI extension point Oracle: ojdbc6-11.2.0.1.0. Jar \ meta-inf \ services \ Java SQL. The Driver

2, such as load Spring – web ServletContainerInitializer: Spring – web – 4.2.0. The jar! \META-INF\services\javax.servlet.ServletContainerInitializer

1.3 JDK examples in action

1, write an interface Command

public interface Command {  
    public void execute();  
}  
Copy the code

2. Write two interface implementation classes TurnOnCommand and TurnOffCommand respectively

public class TurnOnCommand implements Command { public void execute() { System.out.println("Trun on...." ); } } public class TurnOffCommand implements Command { public void execute() { System.out.println("Trun off...." ); }}Copy the code

3. Create an SPI configuration file for com.abc.spi.Com in the resources\ meta-ing \services directory of the project containing the two implementation classes of the interface

Content as follows:

com.abc.spi.TurnOnCommand
com.abc.spi.TurnOffCommand
Copy the code

4. Write the Test class

Public class Test {public static void main(String[] args) {public static void main(String[] args) { serviceLoader=ServiceLoader.load(Command.class); For (Command Command :serviceLoader){command-.execute (); }}}Copy the code

The following figure shows the test results:

1.4. Disadvantages of the JDK’s SPI mechanism

1. The STANDARD SPI in the JDK instantiates all implementations of extension points at once.

2. The JDK’s SPI mechanism does not have support for Ioc and AOP, so Dubbo uses its own SPI mechanism: added support for extension points Ioc and AOP, where one extension point can directly setter and inject other extension points.

2. Dubbo’s SPI convention

2.1 Where are dubbo’s SPI files stored?

All files in dubo-2.3.3. jar\ meta-inf \dubbo\internal under the generated DUbbo jar package are spi extensions

2.2 What are the conventions of DUbbo’s SPI

1, the spi file is stored in the meta-inf \dubbo\internal directory and the file name is the full path of the interface = package name of the interface + interface name.

For example: dubbo – 2.5.3. Jar \ meta-inf \ dubbo \ internal \ com. Alibaba dubbo.. RPC Protocol

2, the inside of the each spi file format is defined as: extension = specific name of the class, such as registries = com. Alibaba. The dubbo. Registry. RegistriesPageHandlerpages.

3. How to extend Dubbo’s SPI

For example, if you want to extend Dubbo’s Protocol, go through the following steps:

1, create a new project in the SRC/main/resources/meta-inf/dubbo directory to create a new file such as org. Apache. Dubbo.. RPC Protocol, write a contents: xxProtocal=com.abc.XxxProtocol

The project catalog is as follows:

2, then create a new XxxProtocol class in this project to implement the Protocol interface, and implement related methods

XxxProtocal.java:

package com.xxx; import org.apache.dubbo.rpc.Protocol; public class XxxProtocol implements Protocol { public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { return new XxxExporter(invoker); } public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException { return new XxxInvoker(type, url); }}Copy the code

XxxExporter. Java:

package com.xxx; import org.apache.dubbo.rpc.support.AbstractExporter; public class XxxExporter<T> extends AbstractExporter<T> { public XxxExporter(Invoker<T> invoker) throws RemotingException{ super(invoker); / /... } public void unexport() { super.unexport(); / /... }}Copy the code

XxxInvoker. Java:

package com.xxx; import org.apache.dubbo.rpc.support.AbstractInvoker; public class XxxInvoker<T> extends AbstractInvoker<T> { public XxxInvoker(Class<T> type, URL url) throws RemotingException{ super(type, url); } protected abstract Object doInvoke(Invocation invocation) throws Throwable { // ... }}Copy the code

Dubbo Provider can be used to create a spi jar for your own dubbo Provider project, and configure it in the spring configuration file as follows:

"Dubbo: protocol XxxProtocol port =" 20000 "name =" "/ >Copy the code

Reference: dubbo.apache.org/en-us/index…