-Adaptive Dubbo source of learning adaptive extension

Foreword

        Basically in the last three weeks between the 9-10-7 and 9-10-6, busy pace of his lost opportunity. In addition to dry before construction of that experience, since only look to participate in software development, some time ago is the busiest. The reason busy, not a large amount of work to be done, but a variety of environmental problems, all kinds of communication and coordination problems. From this project, I realized that the more than one person, the cost spent on communication and coordination really disproportionately enlarged, a good system, coupled with good coordination, greatly improve the overall efficiency. No wonder that year after Huawei finish school work organization and management system with IBM broke out such a strong fighting force. From another point of view, but also to find out why the big companies recruit people pay more attention to personal strength and teamwork of staff, because if people are collaborative work, once it was a great delay will not keep up with the overall progress, and relatively strong in terms of technical ability are more likely to communicate to reach a consensus, collaborative work will be much lower than the cost of a weak ability of people. Avenue one thousand, I choose one, and more to enhance their ability is crucial.

        Syria gossip less, the following continue to Dubbo source of learning. On a talking Dubbo with SPI mechanism to manage and references Bean, similar to the Spring BeanFactory managed bean. SPI achieve a similar "Bean in the container management" function, then the question is, if I want to methods of classes in the SPI managed to call the program is running, and then to determine which implementation class by calling runtime parameters, so contradictory scene should be how to achieve? Then it is up to the adaptive extension mechanism of the Dubbo.

text

        The idea is not difficult to achieve, let's analyze it together. First class method directly call SPI management program runtime is not loaded by SPI class, because it is not yet time to load, so in this case only the first, then determine the method in the proxy class by proxy proxy class, see the need which implementation class to call, go load the implementation class and calls the target method. The first method that is invoked it is only a proxy class that implements the method ultimately call. Add a proxy layer, to achieve a seemingly contradictory scenarios, this can also be seen an important ideological weapon of software development - layered.

        But to realize this idea, it will fall, it is quite complex. You must first determine which methods need to generate proxy classes agent? Dubbo is identified by the class and annotation @Adaptive implemented method. Secondly, how the generated proxy class? Dubbo character string in the first section of the splicing java code, and then use javassit compile the code loaded into the JVM class object obtained by default, and then by the reflection generated proxy class. Finally, after the proxy class generated by what is to confirm the implementation class to load the final call? Dubbo in this regard were the norm, class unified acquisition parameters found to achieve the final call from the URL object. Note the URL is here in Dubbo own definition of a class, the class path org.apache.dubbo.common.URL.

A, @ Adaptive comment

This comment is adaptive extension of the trigger points can be added on in the class with the method. Plus class, the class represents an extension of the class does not need to directly generate the proxy; applied to the method indicates that the method must generate a proxy. On the situation in Dubbo this comment loading classes, only two classes: AdaptiveCompiler and AdaptiveExtensionFactory. In AdaptiveExtensionFactory an example, the source code as follows:

 1 @Adaptive
 2 public class AdaptiveExtensionFactory implements ExtensionFactory {
 3 
 4     private final List<ExtensionFactory> factories;
 5 
 6     public AdaptiveExtensionFactory() {
 7         ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
 8         List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
 9         for (String name : loader.getSupportedExtensions()) {
10             list.add(loader.getExtension(name));
11         }
12         factories = Collections.unmodifiableList(list);
13     }
14 
15     @Override
16     public <T> T getExtension(Class<T> type, String name) {
17         for (ExtensionFactory factory : factories) {
18             T extension = factory.getExtension(type, name);
19             if (extension != null) {
20                 return extension;
21             }
22         }
23         return null;
24     }
25 
26 }

GetExtension seen its own method has been achieved, the property is put factories in two categories: SPIExtensionFactory with SpringExtensionFactory, respectively Dubbo own SPI plant expansion and associated expansion of the plant Spring.

Case notes added to the method to Protocol interface as an example:

 1 @SPI("dubbo")
 2 public interface Protocol {
 3 
 4     int getDefaultPort();
 5 
 6     @Adaptive
 7     <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
 8 
 9     @Adaptive
10     <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
11 
12     void destroy();
13 
14 }

Visible which export method with refer method are added @Adaptive comment

Second, how to generate proxy

Below export service export method Protocol interface, for example, to see how Dubbo agent generates source code is implemented.

In doExportUrlsFor1Protocol ServiceConfig class method, there is such a code section:

1 Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
2 DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
3 Exporter<?> exporter = protocol.export(wrapperInvoker);

Here is exported to the remote trigger point services. Mr. became invoker, and then generate the invoker wrapper class can be seen in the third line invokes the export method protocol interface. protocol properties are:

1 private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

Track getAdaptiveExtension () method, finally found a place to generate the proxy class code: org.apache.dubbo.common.extension.AdaptiveClassCodeGenerator # generate

 1 public String generate() {
 2         // no need to generate adaptive class since there's no adaptive method found.
 3         if (!hasAdaptiveMethod()) {
 4             throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!");
 5         }
 6 
 7         StringBuilder code = new StringBuilder();
 8         code.append(generatePackageInfo());
 9         code.append(generateImports());
10         code.append(generateClassDeclaration());
11         
12         Method[] methods = type.getMethods();
13         for (Method method : methods) {
14             code.append(generateMethod(method));
15         }
16         code.append("}");
17         
18         if (logger.isDebugEnabled()) {
19             logger.debug(code.toString());
20         }
21         return code.toString();
22     }

The entire code splicing process more complex, the individual elements of syntax java assembled, ultimately to give a proxy class codes. If you are interested in a specific code implementation can be viewed on their own, too much trouble, I will not enumerate here.

Then in compiling ExtensionLoader, loading, obtained Class class, the method as follows:

1 private Class<?> createAdaptiveExtensionClass() {
2         String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
3         ClassLoader classLoader = findClassLoader();
4         org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
5         return compiler.compile(code, classLoader);
6     }

Finally, an example of reflection, to give the agent class object.

Third, according to the specified URL to load SPI implementation class, call the method

This step is implemented in the proxy class code for splicing. Tracking above generate (method generateMethod (method) Method):

1 private String generateMethod(Method method) {
2         String methodReturnType = method.getReturnType().getCanonicalName();
3         String methodName = method.getName();
4         String methodContent = generateMethodContent(method);
5         String methodArgs = generateMethodArguments(method);
6         String methodThrows = generateMethodThrows(method);
7         return String.format(CODE_METHOD_DECLARATION, methodReturnType, methodName, methodArgs, methodThrows, methodContent);
8     }

Here will be seen a method divided into five parts: the return value of the method, the method name, content, method parameters, for exception. This is part 5 respectively and then spliced ​​to form a complete method.

The rest are relatively simple, get generateMethodContent () method is mainly concerned about the content of the method.

 1 private String generateMethodContent(Method method) {
 2         Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);
 3         StringBuilder code = new StringBuilder(512);
 4         if (adaptiveAnnotation == null) {
 5             return generateUnsupported(method);
 6         } else {
 7             int urlTypeIndex = getUrlTypeIndex(method);
 8             
 9             // found parameter in URL type
10             if (urlTypeIndex != -1) {
11                 // Null Point check
12                 code.append(generateUrlNullCheck(urlTypeIndex));
13             } else {
14                 // did not find parameter in URL type
15                 code.append(generateUrlAssignmentIndirectly(method));
16             }
17 
18             String[] value = getMethodAdaptiveValue(adaptiveAnnotation);
19 
20             boolean hasInvocation = hasInvocationArgument(method);
21             
22             code.append(generateInvocationArgumentNullCheck(method));
23             
24             code.append(generateExtNameAssignment(value, hasInvocation));
25             // check extName == null?
26             code.append(generateExtNameNullCheck(value));
27             
28             code.append(generateExtensionAssignment());
29 
30             // return statement
31             code.append(generateReturnAndInvocation(method));
32         }
33         
34         return code.toString();
35     }

Due to Dubbo uniform regulations to obtain key dynamic loading through the URL, so we have to look at with this design premise of this method.

First getUrlTypeIndex This method is used to determine parameters of the current method there is no URL, if the return value is the URL parameter index position in the whole parameter list, if not -1.

Since the export method parameters Protocol's no URL, so enter here should method generateUrlAssignmentIndirectly () in else in. This method is to find getUrl method parameters, and then get to. After the implementation of the contents of this method were as follows:

1 if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
2 if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
3 org.apache.dubbo.common.URL url = arg0.getUrl();

Results obtained by the method is performed generateExtNameAssignment:

1 String extName = url.getProtocol();

Result of performing generateExtensionAssignment method were as follows:

1 org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);

 Result of performing generateReturnAndInvocation method were as follows:

1 return extension.export(arg0);

Thus, the proxy class code will be put together out, followed by compiling the compiled class, it is loaded into the JVM, to give the object instance can be done in one go.

end

        At this point, we completed the expansion of the adaptive mechanism of Dubbo. Can be found, the whole process does not place any difficulty, mostly used or seen the usual usage, but by the good hand of Ali middleware engineers a combination, you can achieve such a function, people admire. The next stage is the interpretation of Dubbo service export functionality, so stay tuned.

 

Guess you like

Origin www.cnblogs.com/zzq6032010/p/11219611.html