http://blog.csdn.net/quhongwei_zhanqiu/article/details/41577235
SPI Interface Definition
@spi annotations are defined
Public @interface SPI {
stringvalue () default ""; Specify the default extension point
Only interface classes that have @spi annotations on the interface will find the extension point implementation
The extension points are read from these files in turn
meta-inf/dubbo/internal/ //dubbo Internal implementations of the various extensions are placed in this directory
meta-inf/dubbo/
meta-inf/services/
We take the protocol interface as an example, the interface on the SPI annotation, the default extension point name is Dubbo
@SPI ("Dubbo") public
interface protocol{
}
Various protocols such as Dubboprotocol Injvmprotocolhessianprotocol Webserviceprotocol, etc. are implemented in Dubbo
Dubbo default RPC Module default protocol implementation Dubboprotocol,key to Dubbo
Let's talk about the Extensionloader class.
1. Extensionloader.getextensionloader (Protocol.class)
Each defined SPI interface constructs a Extensionloader instance that is stored in the
Concurrentmap<class<?>,extensionloader<?>> extension_loaders in this map object
2. loadextensionclasses read the implementation class in the extension point
A) Read the value of the SPI annotation first, with the value as the default extension implementation of the key
b) Read the path file sequentially
Meta-inf/dubbo/internal/com.alibaba.dubbo.rpc.protocol
Meta-inf/dubbo/com.alibaba.dubbo.rpc.protocol
Meta-inf/services/com.alibaba.dubbo.rpc.protocol
3. LoadFile reads the contents of the Com.alibaba.dubbo.rpc.Protocol file by line, and each line of content is stored in key/value form.
A) Judgment class implementation (such as: Dubboprotocol) on the M having @adaptive annotation, if annotated, this class as the Protocol protocol to cache the set-up class, read the next line; otherwise the adaptation class is generated by Javasisit modified bytecode, A follow-up introduction to the function of the distribution class if the class implementation is not @adaptive, determine if the implementation class has a constructor for the interface (that is, if the Dubbboprotocol class has a constructor that has an entry parameter of protocol), and some words are cached as wrapper classes to the In this Extensionloader set<class<?>> collection, this is actually a decorative pattern.
b) If the class implementation does not hit @adaptive, determine whether the implementation class exists in the constructor of the interface (that is, if the Dubbboprotocol class has a constructor that has an entry parameter of protocol), or if the wrapper class is cached to this extensionloader set <Class<?>> in the collection, this is actually a decorative pattern.
c) If the object is not set up and is not a wrapped object, that is the specific implementation object of the extension point
There is no @activate annotation on the Find implementation class, and the cache to the variable cachedactivates in the map implements the class cache in cachedclasses, so that it can be used to get
4. Acquire or create a construction object Getadaptiveextension
A) If Cachedadaptiveclass has a value indicating that only one of the implementation classes has been @adaptive, instantiating the object returns
b) If the Cachedadaptiveclass is empty, create a construction with a byte code.
Why to create a construction of a class, a multi-interface implementation, the SPI mechanism is the same, this is the policy model, but we choose which specific strategy in the code execution process. Dubbo uses the unified Data schema Com.alibaba.dubbo.common.URL (which is the Dubbo defined data model is not the JDK's Class), it is interspersed with the entire system execution process, the URL is defined in the Protocol Type field protocol, Different protocols will be set according to the specific business. The Url.getprotocol () value can be Dubbo and can be webservice, either zookeeper or Redis.
The function of the set-up class is to extensionloader according to the value of Url.getprotocol () Extname. GetExtension (extname) selects the specific extension point implementation.
So it is possible to use javasist to generate conditions for setting up a class
1) There must be at least one method in the interface method to @adaptive annotations
2) The method parameter with @adaptive annotation must have a URL type parameter or there is a Geturl () method in the parameter
The following gives the Createadaptiveextensionclasscode () method to generate the code javasist used to generate the Protocol adaptation class
Import com.alibaba.dubbo.common.extension; public class Protocol$adpative implements Com.alibaba.dubbo.rpc.Protocol {//No @adaptive method is transferred to throw exception public void de Stroy () {throw new Unsupportedoperationexception ("Methodpublic abstract void Com.alibaba.dubbo.rpc.Protocol.destroy (
) of Interfacecom.alibaba.dubbo.rpc.Protocol is not Adaptive method! ")}
There is no way to hit the @adaptive if it is transferred to throw exception public int getdefaultport () {Throw newunsupportedoperationexception ( "Method public Abstractint Com.alibaba.dubbo.rpc.Protocol.getDefaultPort () of Interfacecom.alibaba.dubbo.rpc.Protoc
OL is not adaptive method! ");} The export method on the interface is @adaptive registered Publiccom.alibaba.dubbo.rpc.Exporter export (com.alibaba.dubbo.rpc.Invokerar G0) throws com.alibaba.dubbo.rpc.invoker{if (arg0 = = null) throw Newillegalargumentexce
Ption ("com.alibaba.dubbo.rpc.Invokerargument = = null");
URL attribute in parameter class if (arg0.geturl () = = null) Throw Newillegalargumentexception ("com.alibaba.dubbo.rpc.Invokerargument getUrl () = = null");
Get the Unified data Model URL Com.alibaba.dubbo.common.URL url = arg0.geturl () from the incoming parameter; String Extname = (url.getprotocol () = = null?
"Dubbo": Url.getprotocol ()); From the unified data model URL to get the protocol, the protocol name is the SPI extension point implementation class key if (Extname = null) throw new IllegalStateException ("Fail to GetExtension (
com.alibaba.dubbo.rpc.Protocol) name from URL ("+ url.tostring () +") Usekeys ([Protocol]) "); Use the Dubbo Service lookup mechanism to find specific extension points by name com.alibaba.dubbo.rpc.Protocol Extension = (com.alibaba.dubbo.rpc.Protocol)
Extensionloader.getextensionloader (Com.alibaba.dubbo.rpc.Protocol.class). GetExtension (Extname);
The method of adjusting the specific extension point is return Extension.export (arg0); }//Interface Refer method @adaptive Register Publiccom.alibaba.dubbo.rpc.Invoker refer (java.lang.Class arg0, Com.alib ABA.DUBBO.COMMON.URLARG1) throws Java.lang.Class {//Unified data Model URL cannot be null if (arg1 = = null) throw Newillegalar GuMentexception ("url = = null");
Com.alibaba.dubbo.common.URL URL =arg1; From the unified data model URL to get the protocol, the protocol name is the SPI extension point implementation class key String Extname = (url.getprotocol () = = null? "
Dubbo ": Url.getprotocol ()); if (Extname = = null) thrownewillegalstateexception ("Failtogetextension (com.alibaba.dubbo.rpc.Protocol) name from URL
("+ url.tostring () +") Use keys ([protocol]) "); Use the Dubbo Service lookup mechanism to find specific extension points by name com.alibaba.dubbo.rpc.Protocol Extension = (com.alibaba.dubbo.rpc.Protocol)
Extensionloader.getextensionloader (Com.alibaba.dubbo.rpc.Protocol.class). GetExtension (Extname);
The method of adjusting the specific extension point is return Extension.refer (arg0, arg1); }
}
5. Through Createadaptiveextensionclasscode () to generate the Java source code above, to be loaded by the Java Virtual machine execution must be compiled into byte code, Dubbo provides two ways to execute Code compilation 1) using JDK Tool Class compilation 2) to generate bytecode from source code using Javassit.
As shown above:
1) Generate Adaptive Code
2) using Dubbo's SPI expansion mechanism to obtain the compiler of the set-up class
3) Compile the generated adaptive code
Here by the way @Adaptive note the difference between the implementation class and the interface method
1) If there is a hit on the interface method, the Extensionloader.getadaptiveextension () gets the provisioning class, the source code of Java is generated by the preceding procedure, and is compiled into a class load by the compiler. But compiler's implementation strategy choice is also through extensionloader.getadaptiveextension (), if also compiled into a class file by the compiler that would not be a dying cycle. Extensionloader.getadaptiveextension (), for the implementation class on the annotated @adaptive Dubbo SPI extension mechanism, it gets the provisioning class is not generated by the preceding procedure to set the Java source code, Instead, when the extension file is read, the implementation class is annotated @adaptive the class is cached in Extensionloader as the provisioning class, and the call is returned directly
6. Wrap class for extension points on auto wrap
This is a decorative mode implementation, in the JDK input and output stream implementation of a lot of this design, is to enhance the extension point function. Here we take the extension point implementation for the Protocol interface as an example to explain.
As shown in Figure Protocol inheritance relationship Protocolfilterwrapper, Protocollistenerwrapper this two class is a feature that adornment objects use to enhance the implementation of other extensibility points. Protocolfilterwrapper function is mainly in the refer Reference remote service in the transparent setting of a series of filter chain used to record logs, processing timeouts, permissions control and so on functions Protocollistenerwrapper in provider's Exporter,unporter service and consumer refer services, Destory calls when adding listeners, Dubbo provides extensions but does not implement which listeners by default.
How does Dubbo automatically decorate objects on the extension point wrap?
1) When extensionloader.loadfile load the extension point configuration file
A constructor that has an interface type parameter to an extension point class is a package-to-object, which is cached in the collection.
2) in the Extensionloader createextension (name) according to the extension point key to create an extension, the implementation of the extension point is instantiated, in the judgment when there is this extension when there is a wrapper class cache, and some words with the packet converter to enhance the implementation of this extension point function. The following diagram is the implementation process
7. The IOC is known to be one of the three basic functions of spring, and Dubbo's Extensionloader implements a simple IOC mechanism to inject the parameters that the extended implementation relies on when loading the extension implementation, Dubbo the SE in the extended implementation T method and the number of input parameters is a method, try to get the value from the object factory objectfactory to inject into the extension point implementation.
The above figure code should not understand, let's see how Objectfactory is based on the type and name to get the object, Objectfactory is also based on the Dubbo SPI extension mechanism
It is similar to the compiler interface to set the class annotation @adaptive is not generated by Javassist compilation on the class Adaptiveextensionfactory.
Adaptiveextensionfactory holds a collection of all Extensionfactory objects, Dubbo the internal default implementation of the object factory is Spiextensionfactory and Springextensionfactory, The order in which they go through the treemap sequence is first obtained from Spiextensionfactory, if the return empty is obtained from springextensionfactory.
1) Spiextensionfactory factory gets the object to be injected, which is to get the implementation of the Dubbo SPI extension, so the passed parameter type must be an interface type and the interface is @spi annotated, returning a set of matching objects.
2) Springextensionfactory,dubbo uses spring's extension mechanism to make a good integration with spring. When publishing or referencing a service, the spring container is added to the Springextensionfactory factory collection, When Spiextensionfactory does not acquire the object, it traverses the spring container in the springextensionfactory to get the object to be injected.
8. The overall activity chart is given below