博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
5.2 dubbo-compiler源码解析
阅读量:4480 次
发布时间:2019-06-08

本文共 10918 字,大约阅读时间需要 36 分钟。

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

在讲了第一句,在讲了第二句,本章来讲最后一句。

getAdaptiveExtension()层级结构:

1 ExtensionLoader
.getAdaptiveExtension()2 --createAdaptiveExtension()3 ----injectExtension(getAdaptiveExtensionClass())4 ------getAdaptiveExtensionClass()5 --------getExtensionClasses()//从spi文件中查找实现类上具有@Adaptive注解的类6 ----------loadExtensionClasses()7 ------------loadFile(Map
> 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.AdaptiveCompiler2 jdk=com.alibaba.dubbo.common.compiler.support.JdkCompiler3 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
loader = ExtensionLoader.getExtensionLoader(Compiler.class);15 String name = DEFAULT_COMPILER; // copy reference16 if (name != null && name.length() > 0) {17 compiler = loader.getExtension(name);//获取名字为name的实现类的实例,在获取的过程中会完成IOC和AOP18 } 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,最后返回实例。

转载于:https://www.cnblogs.com/java-zhao/p/7469506.html

你可能感兴趣的文章
C# 子线程与主线程通讯方法一
查看>>
006——修改tomacat的编码
查看>>
《C程序设计语言》笔记 (八) UNIX系统接口
查看>>
git常用命令
查看>>
Android必知必会-获取视频文件的截图、缩略图
查看>>
(转)理解Bitblt、StretchBlt与SetDIBitsToDevice、StretchDibits
查看>>
ViurtualBox配置虚拟机Linux的网络环境
查看>>
VLC 媒体播放器
查看>>
勿忘国耻2018/09/18
查看>>
Jenkins部署码云SpringBoot项目
查看>>
多标签分类(multi-label classification)综述
查看>>
史上最全面的Spring-Boot-Cache使用与整合
查看>>
图的遍历(深度优先与广度优先搜索两种方案)
查看>>
快速读入模板
查看>>
\n ^ \t的使用
查看>>
css盒模型
查看>>
探索式测试:测试自动化
查看>>
make install fping
查看>>
面试笔试题
查看>>
MySql可视化工具MySQL Workbench使用教程
查看>>