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
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.
1.3.2 hasNextService method
hasNextService method LazyIterator in charge of loading a configuration file and parse a specific category name.
1.3.3 nextService method
nextService method LazyIterator the implementation class is responsible for loading reflection.
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
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.
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.
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.
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
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.
2) loadDirectory method
Get the configuration file path, get classLoader, and use loadResource method for further processing.
3) loadResource method
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
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
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
Spi way in front SpiExtensionFactory been resolved before.
SpringExtesionFactory is acquired from the corresponding instance ApplicationContext. According to the first name lookup, find it, and then look for the type.
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.
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.
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"