Introduction of SPI
SPI (Service Provider Interface) is a built-in Service discovery mechanism in JDK. There are a number of frameworks that use it for extended discovery of services. Simply put, it is a mechanism for dynamic replacement discovery. The advantage of using the SPI mechanism is decoupling, separating the assembly control logic of a third-party service module from the caller’s business code.
Java SPI
Let’s take a look at the Java SPI mechanism:
SPI follows the following conventions:
- 1. After the service provider provides an implementation of the interface, create a file named “fully qualified name of the interface” in the meta-INF /services directory. The file contains the fully qualified name of the implementation class.
- 2. The JAR package of the interface implementation class is placed in the classpath of the main program;
- 3. The main program loads the implementation module dynamically through java.util.ServiceLoader. It scans the meta-INF /services directory to find the fully qualified name of the implementation class and loads the class into the JVM.
- 4. SPI implementation classes must carry a no-argument constructor;
JavaSPI case
1. Create API modules and formulate specifications
public interface HelloSpi {
String sayHello();
}
Copy the code
2. Create the IMPL module to implement the API interface
Create two classes: man and woman to implement sayHello
public class ManSpi implements HelloSpi { @Override public String sayHello() { return "man say hello"; } } public class WomanSpi implements HelloSpi { @Override public String sayHello() { return "women say hello"; }}Copy the code
Create a meta-INF /services directory under resources and create a file with the same name as the interface classpath
Then configure the full path class name of the implementation class in the file
Create a test module
Rely on apis and IMPL modules
Public class JavaSpiTest {public static void main(String[] args) {ServiceLoader<HelloSpi> serviceLoader=ServiceLoader.load(HelloSpi.class); For (HelloSpi HelloSpi: serviceLoader) { System.out.println(helloSpi.getClass().getName()+":"+helloSpi.sayHello()); }}}Copy the code
test
First, the configuration file configures only ManSpi
Run to see the result
Then change the configuration to WomanSpi
Run to see the result
It is also possible if all are configured
Dubbo SPI
Why did Dubbo write his own SPI
-
- The STANDARD SPI in the JDK instantiates all implementations of extension points at once, which is time-consuming to initialize if there is an extension implementation, but wasteful of resources to load if it is not used
-
- If any extension points fail to load, all extension points are unavailable
-
- Adaptive wrapping of extension points is provided, and injection of other extension points via set is also supported
1. Create API modules and formulate specifications
You need to annotate the interface with SPI annotations
@SPI
public interface HelloService {
String sayHello();
}
Copy the code
2. Create the IMPL module to implement the API interface
API modules need to be introduced, with man and Woman implementing interfaces respectively
public class ManHello implements HelloService { @Override public String sayHello() { return "dubbo man say hello"; } } public class WomanHello implements HelloService { @Override public String sayHello() { return "dubbo woman say hello"; }}Copy the code
Create a meta-INF. dubbo directory in the Resources directory and generate the file with the interface full path class name
Set key=value in the file. Key is equivalent to the ID and value is equivalent to the implementation. Of course, only value can be configured
Create a test module
Here we use Dubbo’s own loader
Public DubboSpiTest {public static void main(String[] args) {// ExtensionLoader<HelloService> extensionLoader=ExtensionLoader.getExtensionLoader(HelloService.class); / / traverse extension point final Set < String > supportedExtensions = extensionLoader. GetSupportedExtensions (); for (String supportedExtension : supportedExtensions) { final HelloService extension = extensionLoader.getExtension(supportedExtension); System.out.println(extension.sayHello()); }}}Copy the code
Viewing the Result
Dubbo SPI @Adaptive
Adaptive function in Dubbo mainly solves the problem of how to dynamically select specific extension points. GetAdaptiveExtension encapsulates all extension points corresponding to the specified interface uniformly and dynamically selects extension points through URL. (All registration information in Dubbo is handled in the form of urls.)
1. Add an interface to the API
@SPI
public interface HelloService {
@Adaptive
String sayHello(URL url);
}
Copy the code
2. Add an implementation to the IMPL
public class ManHello implements HelloService { @Override public String sayHello(URL url) { return "dubbo URL man say hello"; } } public class WomanHello implements HelloService { @Override public String sayHello(URL url) { return "dubbo URL woman say hello"; }}Copy the code
3. Added test method in test module
This is a test so you can fill in any part of the URL,? The following part is HelloService lowercase, followed by the first letter. The = sign is followed by the key in the configuration file that represents the object to be referenced
public class DubboAdaptiveTest {
public static void main(String[] args) {
//hello.service-HelloService
URL url=URL.valueOf("test://localhost/hello?hello.service=man");
final HelloService adaptiveExtension = ExtensionLoader.getExtensionLoader(HelloService.class).getAdaptiveExtension();
final String s = adaptiveExtension.sayHello(url);
System.out.println(s);
}
}
Copy the code
Configure man and view the result
Relocation woman
What happens if you don’t configure it? Execute:
An error is reported, which can be resolved by setting the default:
The priority of the parameter is higher than the default.