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