07_dubbo_compiler
【开始解析最后一行代码 ExtensionLoader.getAdaptiveExtension()】
ExtensionLoader<Protocol> loader = ExtensionLoader.getExtensionLoader(Protocol.class);
final Protocol dubboProtocol = loader.getExtension("dubbo");
final Protocol adaptiveExtension = loader.getAdaptiveExtension();
【getAdaptiveExtension()调用结果】
ExtesionLoader.getAdaptiveExtension()
--createAdaptiveExtension()
----getAdaptiveExtensionClass()
//从spi文件中查找实现类上有@Adaptive注解的类
------getExtensionClasses()
--------loadExtensionClasses()
----------loadFile(Map<String, Class<?>> extensionClasses, String dir)
//第三行代码的重点,如果从spi文件中没找到实现类上有@Adaptive的类,则动态创建类
------createAdaptiveExtensionClass()
【 createAdaptiveExtensionClass()源码 】
private Class<?> createAdaptiveExtensionClass() {
String code = createAdaptiveExtensionClassCode();
ClassLoader classLoader = findClassLoader();
com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
【createAdaptiveExtensionClassCode()方法 】
createAdaptiveExtensionClassCode()方法中会判断:如果一个类中没有@Adaptive注解,直接抛出IllegalStateException异常;如果类有含@Adaptive注解的方法,则为其构造代码;如果类没有含@Adaptive注解的方法的,直接抛出UnsupportedOperationException异常,见下图

【含有@Adaptive注解的方法构造的Protocol$Adaptive对象如下】
package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol {
public void destroy() {
throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public int getDefaultPort() {
throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException {
if (arg1 == null)
throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg1;
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if(extName == null)
throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);
}
public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
if (arg0 == null)
throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null)
throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
com.alibaba.dubbo.common.URL url = arg0.getUrl();
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if(extName == null)
throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.export(arg0);
}
}
【获取Compiler装饰类】
com.alibaba.dubbo.common.compiler.Compiler compiler =
ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
【com.alibaba.dubbo.common.compiler.Compiler 接口】

@SPI 注解的默认值为"javassist",根据上一节的经验,默认获取的Compiler接口的实现类是META-INF/dubbo/internal/com.alibaba.dubbo.common.compiler.Compiler文件中的key为javassist的实现类,如下:
adaptive=com.alibaba.dubbo.common.compiler.support.AdaptiveCompiler
jdk=com.alibaba.dubbo.common.compiler.support.JdkCompiler
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()。
getAdaptiveExtension()首先会调用createAdaptiveExtension()创建实例,然后放入缓存,然后返回。
private T createAdaptiveExtension() {
try {
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), e);
}
}
private Class<?> getAdaptiveExtensionClass() {
/**
* 获取ExtensionClasses和适配类
* 其中适配类cachedAdaptiveClass如果不存在,则需要使用createAdaptiveExtensionClass()进行创建
*/
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
在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进行属性注入,(AdapviceCompiler必须设置响应的setXxx方法),最后返回AdaptiveCompiler对象实例。
【 编译代码并加载为Class<?>对象 】
创建好AdaptiveCompiler对象实例之后,然后执行下面的方法:
Class<?> compile(String code, ClassLoader classLoader)
【AdaptiveCompiler注解】
/**
* AdaptiveCompiler. (SPI, Singleton, ThreadSafe)
*
* @author william.liangf
*/
@Adaptive
public class AdaptiveCompiler implements Compiler {
//默认编译器的名称
private static volatile String DEFAULT_COMPILER; public static void setDefaultCompiler(String compiler) {
DEFAULT_COMPILER = compiler;
}
/**
* 动态代理,在代理类中,存放着真实对象,使用真实对象执行相应的方法
*/
public Class<?> compile(String code, ClassLoader classLoader) {
Compiler compiler;
ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
String name = DEFAULT_COMPILER; // copy reference
if (name != null && name.length() > 0) {
//获取名字为name的实现类实例,在获取的过程中会完成IOC和AOP
compiler = loader.getExtension(name);
} else {
//获取默认的javassistCompiler,调用getExtension(cachedDefaultName)
compiler = loader.getDefaultExtension();
}
//根据获取到的实现类Compiler实例,来执行真正的动态生成类的代码
return compiler.compile(code, classLoader);
} }
【 AbstractCompiler的compile(String code, ClassLoader classLoader)方法】
/**
* Abstract compiler. (SPI, Prototype, ThreadSafe)
*
* @author william.liangf
*/
public abstract class AbstractCompiler implements Compiler { private static final Pattern PACKAGE_PATTERN = Pattern.compile("package\\s+([$_a-zA-Z][$_a-zA-Z0-9\\.]*);"); private static final Pattern CLASS_PATTERN = Pattern.compile("class\\s+([$_a-zA-Z][$_a-zA-Z0-9]*)\\s+"); /*
* 1.根据正则表达式从code中获取包名和类名,组成全类名
* 2.根据全类名使用Class.forName创建Class<?>,如果该类在jvm中存在,则成功,否则抛ClassNotFoundException异常
* 3.执行AdaptiveCompiler的doCompile()方法
*/
public Class<?> compile(String code, ClassLoader classLoader) {
code = code.trim();
Matcher matcher = PACKAGE_PATTERN.matcher(code);
String pkg;
if (matcher.find()) {
pkg = matcher.group(1);
} else {
pkg = "";
}
matcher = CLASS_PATTERN.matcher(code);
String cls;
if (matcher.find()) {
cls = matcher.group(1);
} else {
throw new IllegalArgumentException("No such class name in " + code);
}
String className = pkg != null && pkg.length() > 0 ? pkg + "." + cls : cls;
try {
return Class.forName(className, true, ClassHelper.getCallerClassLoader(getClass()));
} catch (ClassNotFoundException e) {
if (!code.endsWith("}")) {
throw new IllegalStateException("The java code not endsWith \"}\", code: \n" + code + "\n");
}
try {
return doCompile(className, code);
} catch (RuntimeException t) {
throw t;
} catch (Throwable t) {
throw new IllegalStateException("Failed to compile class, cause: " + t.getMessage() + ", class: " + className + ", code: \n" + code + "\n, stack: " + ClassUtils.toString(t));
}
}
} protected abstract Class<?> doCompile(String name, String source) throws Throwable; }
AbstractCompiler的compile(String code, ClassLoader classLoader)方法最终还是会去执行JavassistCompiler的Class<?> doCompiler(String name, String source)方法,在该方法中,使用正则表达式对出传入的源码解析成属性方法等,并使用javassist的API创建Class<?>。
最后,该
final Protocol adaptiveExtension = loader.getAdaptiveExtension();
代码返回的adaptiveExtension = Protocol$Adaptive实例。

【关于ExtensionLoader的几个方法小结】
* ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension():
最终返回的是AdaptiveExtensionFactory实例,其属性factories=[SpringExtensionFactory实例, SpiExtensionFactory实例]
* 不管是获取哪一个SPI接口(除了ExtensionFactory接口)的ExtensionLoader,最终一定会有一个objectFactory = 上述的AdaptiveExtensionFactory实例 *getAdaptiveExtension():作用是获取一个装饰类或动态代理类,如果有@Adaptive注解的类,则直接返回该类的实例,否则返回一个动态代理类的实例(Protocol$Adaptive的实例),之后完成对实例的IOC属性植入,最后返回实例。
*getExtension(String key):作用就是从extensionClasses(即指定SPI接口的没有@Adaptive的实现类)获取指定key的extensionClass,并且实例化,之后完成IOC属性注入,之后再进行dubbo-AOP,最后返回实例
【参考文档】
https://www.cnblogs.com/java-zhao/p/7469506.html
07_dubbo_compiler的更多相关文章
随机推荐
- 实验三敏捷开发与XP实践《Java开发环境的熟悉》实验报告
一.实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim编辑器> 课程 2.完成实验.撰写实验报告,实验报告以博客方式发表在博客园,注意实验报 ...
- 2019 CCPC-Wannafly Winter Camp Day4(Div2, onsite)
slove 6/11 A.夺宝奇兵 Code:zz Thinking:zz 贪心即可.这条路线里,点n1和点n2肯定是相连的,接下来,点(n-1)1和点(n-1)2分别是和n1和点n2相连的,一共有两 ...
- jquery加载单文件vue组件
/**注册组件 */ function registerComponent(name){ dm[name] = {}; Vue.component(name + '-component', funct ...
- APP高级抓包
1.fiddler的证书安装问题时密码问题 问题:我手机下载了fiddler证书 从设置里面安装证书 可是需要输入密码 我没有设置过密码 不知道密码是什么 请问有人遇到过这样的问题的?求解决方法 因为 ...
- 读取Cert格式证书的密钥
不想存储Cert证书内容,只想存储证书密钥,可通过以下实现读取证书的密钥出来: package com.zat.ucop.service.util; import sun.misc.BASE64Enc ...
- C# 直接创建一个DataTable,并为之添加数据(自定义DataTable) 转
DataTable dt=new DataTable("cart"); DataColumn dc1=new DataColumn("prizename",Ty ...
- ubuntu系统复制到其他地方或克隆后,如何正确修改IP及MAC地址的解决方案(图文详解)
修改ip地址 永久修改MAC地址 方法一: 1)编辑“/etc/init.d/rc.local”文件(sudo gedit /etc/init.d/rc.local) 2)在此配置文件的最后面加上如( ...
- c++ 网络编程(一)TCP/UDP windows/linux 下入门级socket通信 客户端与服务端交互代码
原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/9601511.html c++ 网络编程(一)TCP/UDP 入门级客户端与服务端交互代码 网 ...
- 纯CSS让overflow:auto页面滚动条出现时不跳动
现代浏览器滚动条默认是overflow:auto类型的,也就是如果尺寸不足一屏,没有滚动条:超出,出现滚动条.于是,问题来了: 信息流页面,如新浪微博,是从上往下push渲染的.开始只有头部一些信息加 ...
- FocusBI: 使用Python爬虫为BI准备数据源(原创)
关注微信公众号:FocusBI 查看更多文章:加QQ群:808774277 获取学习资料和一起探讨问题. <商业智能教程>pdf下载地址 链接:https://pan.baidu.com/ ...