1. 程式人生 > >5.2 dubbo-compiler源碼解析

5.2 dubbo-compiler源碼解析

ssh 屬性 source 文件 meta ioc blog found des

1         ExtensionLoader<Protocol> loader = ExtensionLoader.getExtensionLoader(Protocol.class);
2         final Protocol dubboProtocol = loader.getExtension("dubbo");
3         final Protocol adaptiveExtension = loader.getAdaptiveExtension();

在2.2 dubbo-spi源碼解析講了第一句,在第四章 dubbo內核之aop源碼解析講了第二句,本章來講最後一句。

getAdaptiveExtension()層級結構:

1 ExtensionLoader<T>.getAdaptiveExtension()
2 --createAdaptiveExtension()
3 ----injectExtension(getAdaptiveExtensionClass())
4 ------getAdaptiveExtensionClass()
5 --------getExtensionClasses()//從spi文件中查找實現類上具有@Adaptive註解的類
6 ----------loadExtensionClasses()
7 ------------loadFile(Map<String, Class<?>> extensionClasses, String dir)
8 --------createAdaptiveExtensionClass()//如果從spi文件中沒有找到實現類上具有@Adaptive註解的類,則動態創建類

這裏最後執行到了createAdaptiveExtensionClass()方法。

1     private Class<?> createAdaptiveExtensionClass() {
2         String code = createAdaptiveExtensionClassCode();
3         ClassLoader classLoader = findClassLoader();
4 com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); 5 return compiler.compile(code, classLoader); 6 }

一 構造代碼串

createAdaptiveExtensionClassCode()方法中會判斷如果一個類中沒有@Adaptive註解的方法,則直接拋出IllegalStateException異常;否則,會為有@Adaptive註解的方法構造代碼,而沒有@Adaptive註解的方法直接拋出UnsupportedOperationException異常。

構造出的結果為:

 1 package com.alibaba.dubbo.rpc;
 2 
 3 import com.alibaba.dubbo.common.extension.ExtensionLoader;
 4 
 5 public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol {
 6     public void destroy() {
 7         throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
 8     }
 9     public int getDefaultPort() {
10         throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
11     }
12     public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException {
13         if (arg1 == null)
14             throw new IllegalArgumentException("url == null");
15         com.alibaba.dubbo.common.URL url = arg1;
16         String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
17         if(extName == null)
18             throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
19         com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
20         return extension.refer(arg0, arg1);
21     }
22     public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
23         if (arg0 == null)
24             throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
25         if (arg0.getUrl() == null)
26             throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
27         com.alibaba.dubbo.common.URL url = arg0.getUrl();
28         String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
29         if(extName == null)
30             throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
31         com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
32         return extension.export(arg0);
33     }
34 }

說明:

  • 該生成類在dubbo2.5.3中export和refer方法聲明處的異常拋出是錯的(在dubbo2.5.4改正了);
  • 類名在dubbo2.5.4之前(包含2.5.4)也是錯的Protocol$Adpative,dubbo2.5.5改正了。

二 獲取Compiler裝飾類

com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();

先看一下com.alibaba.dubbo.common.compiler.Compiler接口:

1 @SPI("javassist")
2 public interface Compiler {
3     Class<?> compile(String code, ClassLoader classLoader);
4 }

@SPI的默認值為javassist,根據上一節的經驗,默認獲取的Compiler接口的實現類將是META-INF/dubbo/internal/com.alibaba.dubbo.common.compiler.Compiler文件中的key為javassit的實現類。文件內容如下:

1 adaptive=com.alibaba.dubbo.common.compiler.support.AdaptiveCompiler
2 jdk=com.alibaba.dubbo.common.compiler.support.JdkCompiler
3 javassist=com.alibaba.dubbo.common.compiler.support.JavassistCompiler

根據上一節對ExtensionFactory的getAdaptiveExtension()的講解,我們最終獲取到的Compiler的AdaptiveExtension將是com.alibaba.dubbo.common.compiler.support.AdaptiveCompiler

來看源碼,首先是獲取ExtensionLoader<com.alibaba.dubbo.common.compiler.Compiler> loader,最終的loader包含如下屬性:

  • Class<?> type = interface com.alibaba.dubbo.common.compiler.Compiler
  • ExtensionFactory objectFactory = AdaptiveExtensionFactory(適配類)
    • factories = [SpringExtensionFactory實例, SpiExtensionFactory實例]

之後,是loader.getAdaptiveExtension()。

在該方法中,首先會調用createAdaptiveExtension()創建實例,之後放入緩存,然後返回。

 1     private T createAdaptiveExtension() {
 2         try {
 3             return injectExtension((T) getAdaptiveExtensionClass().newInstance());
 4         } catch (Exception e) {
 5             throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(),
 6                 e);
 7         }
 8     }
 9 
10     private Class<?> getAdaptiveExtensionClass() {
11         /**
12          * 獲取ExtensionClasses和適配類
13          * 其中適配類cachedAdaptiveClass如果不存在,則需要使用createAdaptiveExtensionClass()進行創建.
14          */
15         getExtensionClasses();
16         if (cachedAdaptiveClass != null) {
17             return cachedAdaptiveClass;
18         }
19         return cachedAdaptiveClass = createAdaptiveExtensionClass();
20     }

在createAdaptiveExtension()中首先會調用getAdaptiveExtensionClass()獲取ExtensionClasses和修飾類,之後將修飾類返回。根據META-INF/dubbo/internal/com.alibaba.dubbo.common.compiler.Compiler文件的內容,最後返回

  • ExtensionClasses
    • "jdk" -> "class com.alibaba.dubbo.common.compiler.support.JdkCompiler"
    • "javassist" -> "class com.alibaba.dubbo.common.compiler.support.JavassistCompiler"
  • cachedAdaptiveClass=class com.alibaba.dubbo.common.compiler.support.AdaptiveCompiler

之後調用AdaptiveCompiler的無參構造器創建AdaptiveCompiler對象實例,然後執行injectExtension(T instance)(這裏沒起作用)為AdaptiveCompiler對象實例註入相應的屬性(AdaptiveCompiler必須提供相應的setter方法),最後返回AdaptiveCompiler對象實例。

三 編譯代碼並加載為Class<?>對象

創建好AdaptiveCompiler對象實例之後,然後執行下面的方法。

Class<?> compile(String code, ClassLoader classLoader)

看一下AdaptiveCompiler全部源碼:

 1 @Adaptive
 2 public class AdaptiveCompiler implements Compiler {
 3     private static volatile String DEFAULT_COMPILER;//默認的編譯器的名字
 4 
 5     public static void setDefaultCompiler(String compiler) {
 6         DEFAULT_COMPILER = compiler;
 7     }
 8 
 9     /**
10      * 典型的動態代理,在代理類中,存放著真實對象,使用真實對象執行相應的方法
11      */
12     public Class<?> compile(String code, ClassLoader classLoader) {
13         Compiler compiler;
14         ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
15         String name = DEFAULT_COMPILER; // copy reference
16         if (name != null && name.length() > 0) {
17             compiler = loader.getExtension(name);//獲取名字為name的實現類的實例,在獲取的過程中會完成IOC和AOP
18         } else {
19             compiler = loader.getDefaultExtension();//獲取默認的JavassitCompiler,調用getExtension(cachedDefaultName)
20         }
21         return compiler.compile(code, classLoader);//根據獲取到的實現類compiler實例,來執行真正的動態生成類的代碼
22     }
23 }

這裏執行的是compiler = loader.getDefaultExtension(),該方法不說了,就是調用了getExtension(cachedDefaultName)生成一個JavassistCompiler的實例。之後就是執行JavassistCompiler的compile(String code, ClassLoader classLoader)方法。

 1 package com.alibaba.dubbo.common.compiler.support;
 2 
 3 import com.alibaba.dubbo.common.compiler.Compiler;
 4 import com.alibaba.dubbo.common.utils.ClassHelper;
 5 
 6 import java.util.regex.Matcher;
 7 import java.util.regex.Pattern;
 8 
 9 /**
10  * Abstract compiler. (SPI, Prototype, ThreadSafe)
11  */
12 public abstract class AbstractCompiler implements Compiler {
13     private static final Pattern PACKAGE_PATTERN = Pattern.compile("package\\s+([$_a-zA-Z][$_a-zA-Z0-9\\.]*);");
14     private static final Pattern CLASS_PATTERN = Pattern.compile("class\\s+([$_a-zA-Z][$_a-zA-Z0-9]*)\\s+");
15 
16     /**
17      * 1 根據正則表達式從code中獲取包名和類名,組成全類名
18      * 2 根據全類名使用Class.forName創建Class<?>,如果該類在jvm中存在,則成功,否則拋出ClassNotFoundException,
19      *   執行doCompile方法。
20      */
21     public Class<?> compile(String code, ClassLoader classLoader) {
22         code = code.trim();
23         Matcher matcher = PACKAGE_PATTERN.matcher(code);
24         String pkg;
25         if (matcher.find()) {
26             pkg = matcher.group(1);
27         } else {
28             pkg = "";
29         }
30         matcher = CLASS_PATTERN.matcher(code);
31         String cls;
32         if (matcher.find()) {
33             cls = matcher.group(1);
34         } else {
35             throw new IllegalArgumentException("No such class name in " + code);
36         }
37         String className = pkg != null && pkg.length() > 0 ? pkg + "." + cls : cls;
38         try {
39             return Class.forName(className, true, ClassHelper.getCallerClassLoader(getClass()));
40         } catch (ClassNotFoundException e) {
41             if (!code.endsWith("}")) {
42                 throw new IllegalStateException("The java code not endsWith \"}\", code: \n" + code + "\n");
43             }
44             try {
45                 return doCompile(className, code);
46             } catch (RuntimeException t) {
47                 throw t;
48             } catch (Throwable t) {
49                 throw new IllegalStateException("Failed to compile class, cause: " + t.getMessage() + ", class: " + className + ", code: \n" + code + "\n, stack: " + ClassUtils.toString(t));
50             }
51         }
52     }
53 
54     protected abstract Class<?> doCompile(String name, String source) throws Throwable;
55 }

該方法會執行JavassistCompiler的Class<?> doCompile(String name, String source)方法了,在該方法中,使用正則表達式對傳入的源碼解析成屬性方法等,並使用javassist的API創建Class<?>。

最後,該final Protocol adaptiveExtension = loader.getAdaptiveExtension();代碼返回的adaptiveExtension = Protocol$Adaptive實例。

總結(再啰嗦一遍):

  • ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()最終返回的是:AdaptiveExtensionFactory實例,其屬性factories = [SpringExtensionFactory實例, SpiExtensionFactory實例]
  • 不管是獲取哪一個SPI接口(除了ExtensionFactory.接口)的ExtensionLoader,最終一定會有一個objectFactory=上述的AdaptiveExtensionFactory實例
  • getAdaptiveExtension():作用就是獲取一個裝飾類或動態代理類的實例, 如果有@Adaptive註解的類,則直接返回該類的實例,否則返回一個動態代理類的實例(例如Protocol$Adaptive的實例),之後完成屬性註入(dubbo-IOC),最後返回實例。
  • getExtension(String key):作用就是從extensionClasses(即指定SPI接口的沒有@Adaptive的實現類)獲取指定key的extensionClass,並且實例化,之後完成屬性註入(dubbo-IOC),再之後完成dubbo-AOP,最後返回實例。

5.2 dubbo-compiler源碼解析