5.2 dubbo-compiler源码解析
ExtensionLoader<Protocol> loader = ExtensionLoader.getExtensionLoader(Protocol.class);
final Protocol dubboProtocol = loader.getExtension("dubbo");
final Protocol adaptiveExtension = loader.getAdaptiveExtension();
在2.2 dubbo-spi源码解析讲了第一句,在第四章 dubbo内核之aop源码解析讲了第二句,本章来讲最后一句。
getAdaptiveExtension()层级结构:
ExtensionLoader<T>.getAdaptiveExtension()
--createAdaptiveExtension()
----injectExtension(getAdaptiveExtensionClass())
------getAdaptiveExtensionClass()
--------getExtensionClasses()//从spi文件中查找实现类上具有@Adaptive注解的类
----------loadExtensionClasses()
------------loadFile(Map<String, Class<?>> extensionClasses, String dir)
--------createAdaptiveExtensionClass()//如果从spi文件中没有找到实现类上具有@Adaptive注解的类,则动态创建类
这里最后执行到了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()方法中会判断如果一个类中没有@Adaptive注解的方法,则直接抛出IllegalStateException异常;否则,会为有@Adaptive注解的方法构造代码,而没有@Adaptive注解的方法直接抛出UnsupportedOperationException异常。
构造出的结果为:
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);
}
}
说明:
- 该生成类在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接口:
@SPI("javassist")
public interface Compiler {
Class<?> compile(String code, ClassLoader classLoader);
}
@SPI的默认值为javassist,根据上一节的经验,默认获取的Compiler接口的实现类将是META-INF/dubbo/internal/com.alibaba.dubbo.common.compiler.Compiler文件中的key为javassit的实现类。文件内容如下:
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()。
在该方法中,首先会调用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对象实例注入相应的属性(AdaptiveCompiler必须提供相应的setter方法),最后返回AdaptiveCompiler对象实例。
三 编译代码并加载为Class<?>对象
创建好AdaptiveCompiler对象实例之后,然后执行下面的方法。
Class<?> compile(String code, ClassLoader classLoader)
看一下AdaptiveCompiler全部源码:
@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) {
compiler = loader.getExtension(name);//获取名字为name的实现类的实例,在获取的过程中会完成IOC和AOP
} else {
compiler = loader.getDefaultExtension();//获取默认的JavassitCompiler,调用getExtension(cachedDefaultName)
}
return compiler.compile(code, classLoader);//根据获取到的实现类compiler实例,来执行真正的动态生成类的代码
}
}
这里执行的是compiler = loader.getDefaultExtension(),该方法不说了,就是调用了getExtension(cachedDefaultName)生成一个JavassistCompiler的实例。之后就是执行JavassistCompiler的compile(String code, ClassLoader classLoader)方法。
package com.alibaba.dubbo.common.compiler.support; import com.alibaba.dubbo.common.compiler.Compiler;
import com.alibaba.dubbo.common.utils.ClassHelper; import java.util.regex.Matcher;
import java.util.regex.Pattern; /**
* Abstract compiler. (SPI, Prototype, ThreadSafe)
*/
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,
* 执行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;
}
该方法会执行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源码解析的更多相关文章
- Dubbo SPI源码解析①
目录 0.Java SPI示例 1.Dubbo SPI示例 2.Dubbo SPI源码分析 SPI英文全称为Service Provider Interface.它的作用就是将接口实现类的全限定名 ...
- 第零章 dubbo源码解析目录
第一章 第一个dubbo项目 第二章 dubbo内核之spi源码解析 2.1 jdk-spi的实现原理 2.2 dubbo-spi源码解析 第三章 dubbo内核之ioc源码解析 第四章 dubb ...
- dubbo源码解析五 --- 集群容错架构设计与原理分析
欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 博客园 Dubbo 入门之二 --- 项目结构解析 博客园 Dubbo 源码分析系列之 ...
- Dubbo 源码解析四 —— 负载均衡LoadBalance
欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 Dubbo 入门之二 --- 项目结构解析 Dubbo 源码分析系列之三 -- 架构原 ...
- dubbo源码解析-spi(4)
前言 本篇是spi的第四篇,本篇讲解的是spi中增加的AOP,还是和上一篇一样,我们先从大家熟悉的spring引出AOP. AOP是老生常谈的话题了,思想都不会是一蹴而就的.比如架构设计从All in ...
- dubbo源码解析-spi(3)
前言 在上一篇的末尾,我们提到了dubbo的spi中增加了IoC和AOP的功能.那么本篇就讲一下这个增加的IoC,spi部分预计会有四篇,因为这东西实在是太重要了.温故而知新,我们先来回顾一下,我们之 ...
- dubbo源码解析-spi(一)
前言 虽然标题是dubbo源码解析,但是本篇并不会出现dubbo的源码,本篇和之前的dubbo源码解析-简单原理.与spring融合一样,为dubbo源码解析专题的知识预热篇. 插播面试题 你是否了解 ...
- 第四章 dubbo内核之aop源码解析
ExtensionLoader<Protocol> loader = ExtensionLoader.getExtensionLoader(Protocol.class); final P ...
- dubbo源码解析-zookeeper创建节点
前言 在之前dubbo源码解析-本地暴露中的前言部分提到了两道高频的面试题,其中一道dubbo中zookeeper做注册中心,如果注册中心集群都挂掉,那发布者和订阅者还能通信吗?在上周的dubbo源码 ...
- Dubbo源码解析之SPI(一):扩展类的加载过程
Dubbo是一款开源的.高性能且轻量级的Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用.智能容错和负载均衡,以及服务自动注册和发现. Dubbo最早是阿里公司内部的RPC框架,于 ...
随机推荐
- rabbitmq学习(八) —— 可靠机制上的“可靠”
接着上一篇,既然已经有了手动ack.confirm机制.return机制,还不够吗? 以下博文转自https://www.jianshu.com/p/6579e48d18ae和https://my.o ...
- jQuery漏掉的东西
prop和attr的区别 attr一般都用来设置和操作元素的自定义属性的,而prop一般都是操作元素的内置属性的(尤其是表单元素的操作我们大部分都在使用prop) each 可以遍历jQuery集合中 ...
- 循序渐进学.Net Core Web Api开发系列【0】:序言与目录
一.序言 我大约在2003年时候开始接触到.NET,最初在.NET framework 1.1版本下写过代码,曾经做过WinForm和ASP.NET开发.大约在2010年的时候转型JAVA环境,这么多 ...
- MySQL Binlog 介绍
Binlog 简介 MySQL中一般有以下几种日志: 日志类型 写入日志的信息 错误日志 记录在启动,运行或停止mysqld时遇到的问题 通用查询日志 记录建立的客户端连接和执行的语句 二进制日志 记 ...
- react运行阶段
运行中可以使用的函数componentWillReceiveProps:父组件修改属性触发,可以修改新属性,修改状态.字面意思,组件将要接收属性,这个函数触发的时机就是组件的属性将要发生改变的时候,但 ...
- 【BZOJ】3751: [NOIP2014]解方程【秦九韶公式】【大整数取模技巧】
3751: [NOIP2014]解方程 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 4856 Solved: 983[Submit][Status ...
- 高性能server分析 - Hadoop的RpcServer
一.Listener Listener线程,当Server处于运行状态时,其负责监听来自客户端的连接,并使用Select模式处理Accept事件. 同时,它开启了一个空闲连接(Idle Connect ...
- C++11 function
#include <iostream> #include <functional> #include <vector> using namespace std; / ...
- C#访问远程主机资源的方法,多种方式
最近要实现访问远程主机的共享目录中的一个文件.遇到了权限问题.google了一下,找到了几种解决方法,记录如下: 一.调用Net use命令 // 使用方法: //if (Connect ...
- MyEclipse10安装Log4E插件
一. Log4E插件下载 下载地址:http://log4e.jayefem.de/content/view/3/2/ 二.安装Log4E插件 将下载下来的压缩包解压缩,如下图所示: 解压缩生成的[d ...