Parsing the source Dubbo SPI (a): extension class loading procedure

Dubbo is an open source, high-performance and lightweight Java RPC framework, which provides three core capabilities: an interface for remote method invocation, intelligent fault tolerance and load balancing, and automatic registration and service discovery.

Dubbo was first inside Ali's RPC framework, open source in 2011, quickly became the industry leader in open source projects of this kind, in February 2018, by voting officially became Apache Foundation incubator project. Currently CreditEase internal company use, there are many projects in Dubbo.

This series of articles by dismantling source Dubbo, Dubbo to help you understand, do know these, and know why.

A, JDK SPI

1.1 What is SPI?

SPI (Service Provider Interface), a service provider interface is JDK built a service delivery mechanisms. When writing the program, are generally recommended oriented programming interface, the benefits of doing so are: reducing the coupling of the program, in favor of the extension.

SPI also adhering to this concept, provides a unified service interface, service providers can provide their own implementation. We are all familiar with the JDBC is based on this mechanism to discover driven provider, whether Ye Hao Oracle, MySQL worth mentioning are the same as in the preparation of the code, but different references jar package only. Later, this concept has also been used in a variety of architecture, such as Dubbo, Eleasticsearch.

1.2 JDK SPI small chestnut

SPI implementations are fully qualified name of the class interface configuration in a file, the configuration file is read by the service loader, loading implementation class.

After understanding the concept, look at a specific example.

1) defines an interface

public interface Operation {
        int operate(int num1, int num2);
}

2) write two simple implementation

public class DivisionOperation implements Operation {
        public int operate(int num1, int num2) {
            System.out.println("run division operation");
            return num1/num2;
        }
}

3) add a profile

In ClassPath path adding a configuration file, the file name is fully qualified class name of the interface, the content to achieve the fully qualified class name of the class, separated by a plurality of implementation class by a newline.

Directory Structure

Parsing the source Dubbo SPI (a): extension class loading procedure

document content

com.api.impl.DivisionOperation
com.api.impl.PlusOperation

4) test procedure

public class JavaSpiTest {
    @Test
    public void testOperation() throws Exception {
        ServiceLoader<Operation> operations = ServiceLoader.load(Operation.class);
        operations.forEach(item->System.out.println("result: " + item.operate(2, 2)));
    } 
}

5) Test Results

run division operation
result:1
run plus operation
result:4

Source code analysis of the 1.3 JDK SPI

Example is very simple to achieve, you can venture a guess about, look at the name "ServiceLoader" should be is a plus class loader configuration file name will achieve concrete realization came loaded according to the type of interface.

Followed by analyzing the source code to understand its implementation principle.

1.3.1 ServiceLoader class

PREFIX defined load paths, reload method initializes LazyIterator, LazyIterator is the core loaded truly loaded. Loaded model can be seen from the name, it is a lazy loading model, only when calls iteration will actually loaded.

Parsing the source Dubbo SPI (a): extension class loading procedure

1.3.2 hasNextService method

hasNextService method LazyIterator in charge of loading a configuration file and parse a specific category name.

Parsing the source Dubbo SPI (a): extension class loading procedure

1.3.3 nextService method

nextService method LazyIterator the implementation class is responsible for loading reflection.

Parsing the source Dubbo SPI (a): extension class loading procedure

After reading the source code, I feel this is the code to optimize space, instantiate all realize nothing actually necessary, to a time-consuming, and secondly, a waste of resources. Dubbo is no mechanism for the use of SPI Java native, but it has been enhanced to enable them to better meet the demand.

Two, Dubbo SPI

2.1 Dubbo SPI little chestnut

Old habits, before dismantling source, first to a chestnut. The example here is a slightly modified on the basis of some of the previous examples herein.

1) defines an interface

Modify the interface, added in Dubbo @SPI comment.

@SPI
public interface Operation {
        int operate(int num1, int num2);
}

2) write two simple implementation

It followed two previous implementation class.

3) add a profile

New configuration file in the directory dubbo.

Directory Structure

Parsing the source Dubbo SPI (a): extension class loading procedure

document content

division=com.api.impl.DivisionOperation
plus=com.api.impl.PlusOperation

4) test procedure

public class DubboSpiTest {
    @Test
    public void testOperation() throws Exception {
          ExtensionLoader<Operation> loader = ExtensionLoader.getExtensionLoader(Operation.class);
          Operation division = loader.getExtension("division");
          System.out.println("result: " + division.operate(1, 2));
    } 
}

5) Test Results

run division operation
result:0

2.2 Dubbo SPI Source

Examples of the above test is very simple, the JDK native and Comparative SPI view, Dubbo of SPI can be obtained according to the configured value kv. In the absence of dismantling source, think about how to achieve.

I might be achieved with double Map Cache: key first layer interface class object, value of a Map; second layer extension key (key in the configuration file), value for the realization of class Class. Implementation of lazy loading, when the method of operation creates an empty map. Find a class object implementation class of existing cache in real time to acquire, find direct return, can not find it loaded and cached according to the configuration file.

Dubbo is how to achieve it?

2.2.1 getExtensionLoader 方法

First, let's dismantling getExtensionLoader method.

Parsing the source Dubbo SPI (a): extension class loading procedure

This is a static factory method, requires incoming type must have SPI interfaces and annotations made a cache with a map, key for the class object interfaces, and value is ExtensionLoader object.

2.2.2 getExtension method

GetExtension method of dismantling again ExtensionLoader.

Parsing the source Dubbo SPI (a): extension class loading procedure

This code is not complicated, if the incoming parameter is 'true', the default extension class instance is returned; otherwise, obtain an instance from the cache, if they are taken from the cache, if not on the new. To do with the map cache, the cache holder object, and the object holder stored in the extended class. Double-check with the volatile keyword and create problems to deal with multi-threading, which is commonly used in the wording of a single case model.

2.2.3 createExtension method

Focuses on createExtension method.

Parsing the source Dubbo SPI (a): extension class loading procedure

This code consists of several parts:

  • Obtain the corresponding class according to the incoming extension.
  • Gets an instance of class according to the cache, if not, create objects through reflection and placed in the cache.
  • Dependency injection, to complete the initialization object instance.
  • Create a wrapper object. That is, the returned object here is not necessarily a specific category, it may be wrapped object.

The second nothing to say, we have to analyze the focus of 1,3,4 three parts.

1) getExtensionClasses method

Parsing the source Dubbo SPI (a): extension class loading procedure

Old routines, acquired from the cache, if not created and added to the cache. Here is a relation name cache and the class extension. This extension is the key in the configuration file. Before creating the first cache a bit qualified name of the interface. Loading a configuration file path is the following few.

Parsing the source Dubbo SPI (a): extension class loading procedure

2) loadDirectory method

Parsing the source Dubbo SPI (a): extension class loading procedure

Get the configuration file path, get classLoader, and use loadResource method for further processing.

3) loadResource method

Parsing the source Dubbo SPI (a): extension class loading procedure

Parsing the source Dubbo SPI (a): extension class loading procedure

loadResource load the configuration file, and parses the contents of the configuration file. loadClass method of operating a different cache.

First, determine whether there Adaptive notes, any cached cacheAdaptiveClass (cache structure class); and then determine whether wrapperclasses, is then cached to cacheWrapperClass in (cache structure Set); if none of the above, this class is a normal class mapping relational storage class and name to cacheNames in (cache structure is map).

Basically getExtensionClasses method to analyze finished, you can see that, in fact, is not very complicated.

2.2.4 IOC

1) injectExtension method

Parsing the source Dubbo SPI (a): extension class loading procedure

This method implements dependency injection, i.e. IOC. The method of obtaining the first instance by reflection; then traverse, obtaining setter method; objectFactory then acquired from the dependent objects; and finally into the setter method relies invoked by reflection.

objectFactory variable type AdaptiveExtensionFactory.

2)AdaptiveExtensionFactory

Parsing the source Dubbo SPI (a): extension class loading procedure

The class which has a list ExtensionFactory used to store other types of ExtensionFactory. Dubbo provides two ExtensionFactory, one is SpiExtensionFactory, used to create the adaptive expansion; the other is SpringExtesionFactory, for obtaining extended from the IOC Spring container. A profile in dubbo-common module, a module dubbo-config.

Profiles

Parsing the source Dubbo SPI (a): extension class loading procedure

Parsing the source Dubbo SPI (a): extension class loading procedure

Spi way in front SpiExtensionFactory been resolved before.

Parsing the source Dubbo SPI (a): extension class loading procedure

SpringExtesionFactory is acquired from the corresponding instance ApplicationContext. According to the first name lookup, find it, and then look for the type.

Parsing the source Dubbo SPI (a): extension class loading procedure

Dependency injection is also part of the dismantling is complete, take a look at the last part of the dismantling of the code.

2.2.5 AOP

Create a wrapper object part, wrapper objects that come from? Remember the first step before dismantling it, loadClass method has several cache, which is wrapperclasses cache class of these wrapper.

Parsing the source Dubbo SPI (a): extension class loading procedure

As can be seen from the code, as long as there are the constructor and there is only one parameter, and this parameter is passed in this interface type, namely wrapper class.

Parsing the source Dubbo SPI (a): extension class loading procedure

Create wrapper instances where the cycle, the first instance as a parameter of a constructor to create a wrapper object via reflection, and then injected again dependent on the wrapper.

See here, some may have questions: Why create a wrapper objects? Actually very simple, the system wanted to do something else before and after chanting real call. This is a bit similar to the spring of the aop.

Third, the summary

This paper briefly describes the JDK and the SPI SPI usage of Dubbo, analyzed the JDK source of SPI and the SPI Dubbo source. As can be seen in the process of dismantling, Dubbo source is still very worth reading. In achieving consider it very thoroughly, not only for multi-threaded processing, multi-cache, there IOC, the AOP process. However, Dubbo SPI's so simple? Of course not, this is only the loading process dismantling the extension class, Dubbo SPI there's a very complex extension points - adaptive mechanism. Information on how funeral, please listen next time decomposition ~ ~

Author: Department of Payment and Settlement letter should pay for research and development senior engineer R & D team Java Zhengxiang Bin

Original starting in the "field guide"

Guess you like

Origin blog.51cto.com/14159827/2475733