Registration and discovery of Dubbo services

preface

Recently, I participated in a project based on Dubbo. During the development process, some colleagues seemed not to know much about the registration and discovery mechanism of Dubbo service. So I took time out to briefly chat with him about what I know about Dubbo mechanics.

The body of the

Java SPI

SPI stands for service Provider Interface. It is a mechanism for dynamically loading service implementers. With JavaSPI, we can elegantly obtain all implementation classes of an interface.

It is worth noting that the Java SPI used must have the following premises:

1. Create a directory in the classpath. The name of the directory must be meta-INF /service

2. Create a Properties file in the directory that meets the following requirements:

  • The file name must be the full path name of the extended interface
  • All the implementation classes of the extension interface are described inside the file
  • The encoding format of the file isUTF-8

3. Discover through the loading mechanism of java.util.ServiceLoader

The meta-INF folder is an information package in which files and directories are approved and interpreted by the Java 2 platform to configure applications, extenders, class loaders, and services.

Mysql-connector-java is the most common mysql driver that can be implemented with JavaSPI:

  • JavaDefines thejava.sql.DriverUsed forAPIThe interface is used to connect to the database, but it is not implemented.
  • JavathroughSPIMechanisms can be adapted to different data sources as long as they drive the class implementationjava.sql.DriverInterface.

One drawback of JavaSPI, however, is that JavaSPI iterates through the SPI configuration file and instantiates the entire implementation class when looking for an extension implementation class. Assuming an implementation class initialization process is expensive and time consuming, but you don’t need it in your code, it wastes resources. So Java SPI cannot load implementation classes on demand.

Dubbo SPI

The way Dubbo discovers service implementers is also based on SPI design ideas, but differs from JavaSPI.

Dubbo’s convention for configuration file directories, unlike the Java SPI, divides Dubbo into three categories:

  • Meta-inf/services/directory: in this directorySPIConfiguration files are used for compatibilityJava SPI
  • Meta-inf/dubbo/directory: This directory stores user-defined filesSPIConfiguration file.
  • Meta-inf/dubbo/internal/directory: This directory is used for storingDubboInternally usedSPIConfiguration file.

The corresponding relationship between the Dubbo external interface and its implementation class is configured in a file. ExtensionLoader will parse the file and add the data to a Map. We call the process of obtaining the implementation class of the external interface as obtaining extension points, which can be divided into three types:

Adaptive extension point: It matches by class. There can only be one of a class

ExtensionLoader.getExtensionLoader(xxx.class).getAdaptiveExtension();
Copy the code

Specifies the extension point of the name

ExtensionLoader.getExtensionLoader(xxx.class).getExtension(name);
Copy the code

Activation extension point

ExtensionLoader.getExtensionLoader(xxx.class).getActivateExtension(url, key);
Copy the code

The following uses the Dubbo Protocol (RPC) as an example

Dubbo officially supports 10 communication protocols. Dubbo uses SPI mechanisms to accommodate different protocols

<dubbo:protocol name="dubbo"  port="20880"  threads="1000" />
Copy the code

The Dubbo Protocol extends in an adaptive manner

Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
Copy the code

Dubbo provides a Protocol extension point for Dubbo by default

  • @SPI("dubbo"): defines extension points
  • @AdaptiveThe target tag implements an adapter class that obtains extension points in the three ways described above, such as@Adaptive({Constants.PROXY_KEY})Is the adaptive extension point
@SPI("dubbo")  
public interface Protocol {  
      
    int getDefaultPort(a);  
  
    @Adaptive  
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;  
  
    @Adaptive  
    <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;  


    void destroy(a);  
  
}
Copy the code

Workflow of Dubbo SPI

Dubbo SPI does not instantiate all implementation classes at once, but only uses ExtensionLoader to get extension points when needed. Through reflection and caching mechanism, the performance of dynamically loading service implementers is further improved.

The process of loading extension points by ExtensionLoader can be summarized as follows:

1. Get an ExtensionLoader from the class name

2. Find the implementation class instance from ExtensionLoader by the defined name

  • If a cache exists, the instance is fetched directly from the cache
  • If there is no cache, create an instance by reflection and then execute set

    Method dependency injection. Wrap another layer if you find any packaging classes. If it’s marked@Adaptive, will place the instance in the cache.

The way Dubbo registers and references services

We don’t need to worry about Dubbo SPI in real life. Dubbo itself encapsulates the Dubbo registration and reference services more succinctly.

Dubbo references external services

  • @ReferenceWhen used on the consumer side, what service is used on the server side
@Reference(interfaceClass = IUserService.class,retries=0,check=false,timeout = 50000,mockClass=MockUserService.class)
private IUserService iUserService;
Copy the code

Can be equivalent to this configuration in XML

<! <dubbo: Reference id="user" interface="com.luo.api.service.IUserService" retries="0" timeout="50000"
                 check="false"
                 mock="com.luo.api.service.mockimpl.MockUserService" />
Copy the code

Dubbo registered for external services

  • @ServiceUsed in service providers, declared in classes or interfaces.
@Service(cluster ="failfast")
public class UserServiceImpl implements IUserService{}Copy the code

Can be equivalent to this configuration in XML

<! -- Dubbo management platform interface --> <bean id="UserService" class="com.luo.producer.rpcservice.UserServiceImpl" />
<dubbo:service interface="com.luo.api.service.IUserService" ref="UserService"  cluster="failfast"/>
Copy the code