This is a study note for the hook course
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.
The SPI in the JDK
If you want to use SPI functionality in Java, you provide the standard service interface first, and then the associated interface implementation and caller. In this way, the corresponding interface implementation can be queried through the agreed information in the 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; The directory structure of the code implementation project is as follows
First create a new project and then create a moudle interface for the interface definition
public interface HelloService {
String sayHello();
}
Copy the code
Create an implementation interface moudle to define the interface implementation class
public class DogHelloService implements HelloService {
@Override
public String sayHello() {
return "wang wang"; }}Copy the code
public class HumanHelloService implements HelloService {
@Override
public String sayHello() {
return "Hello, hello"; }}Copy the code
Create a file named “interface fully qualified Name” in the meta-INF /services directory. The content is the fully qualified name of the implementation class
The main program loads the implementation module dynamically through java.util.Serviceloader, which loads the class into the JVM by scanning the meta-INF /services directory for the fully qualified name of the implementation class
public class JavaSpiMain {
public static void main(String[] args) {
final ServiceLoader<HelloService> helloServices = ServiceLoader.load(HelloService.class);
for (HelloService helloService : helloServices){
System.out.println(helloService.getClass().getName() + ":"+ helloService.sayHello()); }}}Copy the code
Dubbo SPI
Dubbo makes extensive use of SPI as an extension point, allowing you to customize your own implementation classes by implementing the same interface. Common protocols, such as load balancing, can be customized and extended by SPI. All of the implemented extension points that already exist in Dubbo.
Dubbo already implements good extension points
Dubbo uses extension points to create a project with the following directory structure
Defines the interface
@SPI
public interface HelloService {
String sayHello();
}
Copy the code
Defining the implementation class
public class DogHelloService implements HelloService{
@Override
public String sayHello() {
return "wang wang"; }}Copy the code
public class HumanHelloService implements HelloService{
@Override
public String sayHello() {
return "Hello, hello"; }}Copy the code
Create a meta-INF. dubbo folder and create a file named “Interface fully qualified Name” with key as the alias and value as the fully qualified class name of the implementation class.
use
public class DubboSpiMain {
public static void main(String[] args) {
// Get the extension loader
ExtensionLoader<HelloService> extensionLoader = ExtensionLoader.getExtensionLoader(HelloService.class);
// Iterate over all supported extension points meta-inf.dubbo
Set<String> extensions = extensionLoader.getSupportedExtensions();
for (String extension : extensions){
Stringresult = extensionLoader.getExtension(extension).sayHello(); System.out.println(result); }}}Copy the code
The results
Adaptive in Dubbo SPI
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.) This is implemented in the same way. Modify the interface based on the above code to add a method with an input parameter of URL
@SPI("human") The value in the annotation represents the alias of the default implementation class, HumanHelloService, which is implemented by default if the URL is specified
public interface HelloService {
String sayHello();
@Adaptive
String sayHello(URL url);
}
Copy the code
The implementation class
public class DogHelloService implements HelloService{
@Override
public String sayHello() {
return "wang wang";
}
@Override
public String sayHello(URL url) {
return "wang url"; }}Copy the code
public class HumanHelloService implements HelloService{
@Override
public String sayHello() {
return "Hello, hello";
}
@Override
public String sayHello(URL url) {
return "hello url"; }}Copy the code
use
public class DubboAdaptiveMain {
public static void main(String[] args) {
URL url = URL.valueOf("test://localhost/hello? hello.service=dog");
HelloService adaptiveExtension = ExtensionLoader.getExtensionLoader(HelloService.class).getAdaptiveExtension();
Stringmsg = adaptiveExtension.sayHello(url); System.out.println(msg); }}Copy the code
URL = url.valueof (“test://localhost/hello? hello.service=dog”); ,? You can specify whatever you want, because this is just a demo, right? Hello. service is the name of the interface HelloService, and = is the key defined in the file.
The results
If no implementation class is specified, the default implementation class is implemented