Dubbo 2.7 AOP与动态编译源码剖析
学习目标
完成本章后,你能够:
- 说明Dubbo AOP与Spring AOP在实现机制上的本质区别
- 阐述ProtocolFilterWrapper的Filter链织入原理
- 完整解读JavassistCompiler.doCompile的编译流程
- 说出动态编译在Dubbo中的三个核心应用场景
- 对比JavassistCompiler与JdkCompiler的优劣势
1. Dubbo AOP实现原理
1.1 Dubbo AOP vs Spring AOP
java
/**
* 两种AOP实现方式的本质区别
*
* Spring AOP:
* - 基于代理:JDK动态代理 + CGLIB子类代理
* - 织入点:Bean初始化后置处理
* - 切面定义:@Before/@After/@Around 注解
* - 切入点:表达式匹配方法签名
*
* Dubbo AOP:
* - 基于装饰器(Wrapper模式):无代理,直接包装
* - 织入点:ExtensionLoader.createExtension()
* - 增强来源:Wrapper类通过构造器接收目标对象
* - 切入点:所有Wrapper类都会被自动织入
*
* 本质区别:
* - Spring AOP是"横切关注点"的分离
* - Dubbo AOP是"职责链"的串联
*/
public class AopComparison {
/**
* Dubbo AOP的核心价值:
*
* 1. 无代理开销:不生成运行时类,性能更高
* 2. SPI统一:每个Wrapper都是一个扩展点,可插拔
* 3. 顺序可控:通过Wrapper类的加载顺序控制执行顺序
* 4. 编译期确定:链结构在ExtensionLoader初始化时确定,运行时不变
*/
}
1.2 ProtocolFilterWrapper源码解析
java
/**
* ProtocolFilterWrapper ------ Filter链的织入器
*
* 职责:
* 1. export时:将Provider端的Filter链织入Invoker之前
* 2. refer时:将Consumer端的Filter链织入Invoker之前
*
* 装饰器模式:ProtocolFilterWrapper 包装 Protocol 的 export/refer
*/
public class ProtocolFilterWrapperSimulation implements Protocol {
private final Protocol protocol;
public ProtocolFilterWrapperSimulation(Protocol protocol) {
this.protocol = protocol;
}
@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
// ===== Provider端:注册中心协议跳过Filter链 =====
// 如果目标是注册中心(registry://),不织入Filter
if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
return protocol.export(invoker);
}
// ===== Provider端:构建Filter链 =====
// 从URL获取配置的Filter列表 + 自动激活的Filter列表
// 例如URL为 dubbo://...?filter=customFilter1,customFilter2
// 最终调用的Filter链 = 自动激活的Filter + 用户配置的Filter
Invoker<T> filterChained = buildInvokerChain(
invoker,
Constants.SERVICE_FILTER_KEY, // key = "service.filter"
Constants.PROVIDER // group = "provider"
);
return protocol.export(filterChained);
}
@Override
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
// ===== Consumer端:注册中心协议跳过Filter链 =====
if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
return protocol.refer(type, url);
}
// ===== Consumer端:构建Filter链 =====
Invoker<T> filterChained = buildInvokerChain(
protocol.refer(type, url),
Constants.REFERENCE_FILTER_KEY, // key = "reference.filter"
Constants.CONSUMER // group = "consumer"
);
return filterChained;
}
/**
* 构建Filter链------装饰器模式的核心
*
* 返回的结构:
* FilterN(FilterN-1(...(Filter1(原始Invoker))...))
*
* 调用顺序:
* FilterN.invoke() → FilterN-1.invoke() → ... → Filter1.invoke() → 原始Invoker.invoke()
*/
private <T> Invoker<T> buildInvokerChain(
final Invoker<T> invoker, String key, String group) {
Invoker<T> last = invoker;
// ===== 1. 获取所有激活的Filter =====
// 从ExtensionLoader获取按order排序后的Filter列表
List<Filter> filters = ExtensionLoader
.getExtensionLoader(Filter.class)
.getActivateExtension(invoker.getUrl(), key, group);
// ===== 2. 逆序遍历,构建装饰链 =====
// 逆序遍历是因为最内层Filter先创建,最外层最后创建
if (filters.size() > 0) {
for (int i = filters.size() - 1; i >= 0; i--) {
final Filter filter = filters.get(i);
final Invoker<T> next = last;
// ===== 3. 创建匿名Invoker作为Filter的装饰层 =====
last = new Invoker<T>() {
@Override
public Class<T> getInterface() {
return invoker.getInterface();
}
@Override
public URL getUrl() {
return invoker.getUrl();
}
@Override
public boolean isAvailable() {
return invoker.isAvailable();
}
@Override
public Result invoke(Invocation invocation)
throws RpcException {
// 委托给Filter执行
return filter.invoke(next, invocation);
}
@Override
public void destroy() {
invoker.destroy();
}
};
}
}
return last; // 返回最外层的装饰Invoker
}
}
1.3 Provider端Filter执行序列
java
/**
* Provider端8个内置Filter的执行顺序与职责
*/
public class ProviderFilterChain {
/**
* 调用链顺序(从外到内):
*
* EchoFilter → ClassLoaderFilter → GenericFilter → ContextFilter
* → TraceFilter → TimeoutFilter → MonitorFilter → ExceptionFilter
* → 业务Invoker
*
* 以表格形式展示每个Filter的职责:
*/
public static class FilterDescription {
public static final Map<String, String> PROVIDER_FILTERS = Map.ofEntries(
Map.entry("EchoFilter",
"回音测试:检测服务是否存活,用于Dubbo Admin的健康检查"),
Map.entry("ClassLoaderFilter",
"ClassLoader切换:将当前线程的ClassLoader切换为Provider的ClassLoader"),
Map.entry("GenericFilter",
"泛化调用支持:处理泛化服务(GenericService)的调用请求"),
Map.entry("ContextFilter",
"上下文传递:从Invocation.attachments中提取隐式参数并放回RpcContext"),
Map.entry("TraceFilter",
"链路追踪:将traceId等追踪信息传递给调用链"),
Map.entry("TimeoutFilter",
"超时告警:检测调用是否超时,记录超时日志"),
Map.entry("MonitorFilter",
"监控统计:记录调用次数、成功/失败数、耗时等监控数据"),
Map.entry("ExceptionFilter",
"异常包装:将Provider端业务异常包装为标准RpcResult")
);
}
}
2. 动态编译Compile源码解析
2.1 Compile扩展点体系
java
/**
* Dubbo动态编译的扩展点体系
*
* @SPI("javassist")
* public interface Compile {
* Class<?> compile(String code, ClassLoader classLoader);
* }
*
* 实现:
* - JavassistCompiler(默认):基于Javassist的字节码编译
* - JdkCompiler:基于JDK Compiler API的源码编译
*
* Javassist advantage over JDK:
* - 不需要生成.java文件到磁盘
* - 字节码直接写入ClassLoader
* - 性能更高(跳过javac阶段)
*/
public class CompileExtensionSystem {
/**
* 动态编译的三个核心应用场景:
*
* 1. 动态生成Adaptive类
* - ExtensionLoader.createAdaptiveExtensionClass()
* - 为@Adaptive注解标注的方法自动生成代理类
*
* 2. 动态生成Wrapper类
* - Wrapper.makeWrapper(Class)
* - 为每个扩展接口生成高效的无反射调用包装类
*
* 3. 动态生成Proxy类
* - Proxy.getProxy(ClassLoader, Class[])
* - 为服务接口生成动态代理
*/
}
2.2 JavassistCompiler.doCompile 源码详解
java
/**
* JavassistCompiler ------ Dubbo默认的动态编译器
*
* 继承了AbstractCompiler,重写doCompile方法
* 核心思路:
* ① 正则掰开Java源代码的各个片段
* ② 用CtClassBuilder逐片段构造Javassist CtClass对象
* ③ 将CtClass转换为JVM Class对象
*/
public class JavassistCompilerSourceCode extends AbstractCompiler {
// ===== 正则Pattern ------ 用于提取源代码片段 =====
/** 提取 import xx.xx 语句 */
private static final Pattern IMPORT_PATTERN =
Pattern.compile("import\\s+([\\w\\.\\*]+);\n");
/** 提取 extends XXX 声明 */
private static final Pattern EXTENDS_PATTERN =
Pattern.compile("\\s+extends\\s+([\\w\\.]+)[^\\{]*\\{\n");
/** 提取 implements XXX 声明 */
private static final Pattern IMPLEMENTS_PATTERN =
Pattern.compile("\\s+implements\\s+([\\w\\.]+)\\s*\\{\n");
/** 提取方法声明(private/public/protected开头) */
private static final Pattern METHODS_PATTERN =
Pattern.compile("\n(private|public|protected)\\s+");
/** 提取字段赋值语句(含等号的语句) */
private static final Pattern FIELD_PATTERN =
Pattern.compile("[^\n]+=[^\n]+;");
/**
* doCompile核心流程
*
* 输入:一个完整的Java源代码字符串
* 输出:编译后的Class对象
*/
@Override
public Class<?> doCompile(String name, String source) throws Throwable {
// ===== 步骤①:创建CtClassBuilder =====
// CtClassBuilder是Dubbo封装的Javassist类构造器
CtClassBuilder builder = new CtClassBuilder();
builder.setClassName(name);
// ===== 步骤②:提取import语句 =====
// 正则扫描 import java.util.Map; → 加入builder
Matcher matcher = IMPORT_PATTERN.matcher(source);
while (matcher.find()) {
builder.addImports(matcher.group(1).trim());
}
// ===== 步骤③:提取extends父类 =====
// 正则匹配 "extends SomeClass {"
matcher = EXTENDS_PATTERN.matcher(source);
if (matcher.find()) {
builder.setSuperClassName(matcher.group(1).trim());
}
// ===== 步骤④:提取implements接口 =====
// 正则匹配 "implements InterfaceA, InterfaceB {"
matcher = IMPLEMENTS_PATTERN.matcher(source);
if (matcher.find()) {
String[] ifaces = matcher.group(1).trim().split("\\,");
Arrays.stream(ifaces)
.forEach(i -> builder.addInterface(i.trim()));
}
// ===== 步骤⑤:提取方法体 =====
// 截取第一个左花括号 { 之后的内容
String body = source.substring(
source.indexOf('{') + 1,
source.length() - 1
);
// 用正则拆分方法(以private/public/protected开头)
String[] methods = METHODS_PATTERN.split(body);
String className = ClassUtils.getSimpleClassName(name);
for (String method : methods) {
String trimmed = method.trim();
if (trimmed.isEmpty()) continue;
// ===== 步骤⑥:分类处理 =====
if (trimmed.startsWith(className)) {
// 构造器方法(方法名 == 类名)
builder.addConstructor("public " + trimmed);
} else if (FIELD_PATTERN.matcher(trimmed).matches()) {
// 字段赋值语句
builder.addField("private " + trimmed);
} else {
// 普通方法
builder.addMethod("public " + trimmed);
}
}
// ===== 步骤⑦:构建CtClass并转换为Class对象 =====
ClassLoader classLoader = ClassUtils.getCallerClassLoader(getClass());
CtClass ctClass = builder.build(classLoader);
return ctClass.toClass(classLoader, getClass().getProtectionDomain());
}
}
2.3 Adaptive类动态生成
java
/**
* Adaptive类动态生成的完整流程
*
* ExtensionLoader.createAdaptiveExtensionClass() 的核心逻辑:
* 1. 扫描接口的所有方法,找出标注了 @Adaptive 的方法
* 2. 为每个 @Adaptive 方法生成代理代码字符串
* 3. 用 javassist 编译代码字符串生成 Class
* 4. 实例化并缓存在 cachedAdaptiveInstance 中
*/
public class AdaptiveClassGeneration {
/**
* 自动生成 Adaptive 类的源代码(简化版)
*/
public String generateAdaptiveCode(Class<?> type) {
SPI spiAnnotation = type.getAnnotation(SPI.class);
String defaultExtName = spiAnnotation.value(); // 默认扩展名
StringBuilder code = new StringBuilder();
// ===== 包声明 =====
code.append("package ").append(type.getPackage().getName()).append(";\n\n");
// ===== import声明 =====
code.append("import org.apache.dubbo.common.extension.ExtensionLoader;\n\n");
// ===== 类声明 =====
code.append("public class ").append(type.getSimpleName())
.append("$Adaptive implements ").append(type.getName()).append(" {\n\n");
// ===== 遍历所有方法 =====
for (Method method : type.getMethods()) {
if (!method.isAnnotationPresent(Adaptive.class)) {
// 未标注 @Adaptive 的方法生成异常抛出
code.append(" public ").append(method.getReturnType().getName())
.append(" ").append(method.getName()).append("(");
// 参数列表
Class<?>[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
if (i > 0) code.append(", ");
code.append(paramTypes[i].getName()).append(" arg").append(i);
}
code.append(") {\n");
code.append(" throw new UnsupportedOperationException(\"")
.append("The method ").append(method.getName())
.append(" of interface ").append(type.getName())
.append(" is not adaptive method!\");\n");
code.append(" }\n\n");
continue;
}
// ===== 标注了 @Adaptive 的方法 → 生成委托代码 =====
code.append(" public ").append(method.getReturnType().getName())
.append(" ").append(method.getName()).append("(");
// ... (参数生成)
code.append(") {\n");
// 核心逻辑:
// 1. 从URL获取扩展名
code.append(" String extName = ").append(extractExtName(method))
.append(";\n");
code.append(" if (extName == null) {\n");
code.append(" extName = \"").append(defaultExtName).append("\";\n");
code.append(" }\n");
// 2. 获取具体扩展实现
code.append(" ").append(type.getName()).append(" extension = ")
.append("ExtensionLoader.getExtensionLoader(")
.append(type.getName()).append(".class).getExtension(extName);\n");
// 3. 委托调用
code.append(" return extension.").append(method.getName())
.append("(arg0, arg1);\n");
code.append(" }\n\n");
}
code.append("}\n");
return code.toString();
}
/**
* 从URL提取扩展名的逻辑
* @Adaptive注解中可以指定具体的key,如@Adaptive({"protocol"})
*/
private String extractExtName(Method method) {
Adaptive adaptive = method.getAnnotation(Adaptive.class);
String[] keys = adaptive.value();
if (keys.length == 0) {
// 默认规则:从接口名提取key
// Protocol → protocol, Transporter → transporter
String interfaceName = method.getDeclaringClass().getSimpleName();
return interfaceName.substring(0, 1).toLowerCase()
+ interfaceName.substring(1);
}
// 返回第一个指定的key
return keys[0];
}
}
2.4 Javassist vs JDK 编译器对比
java
/**
* JavassistCompiler vs JdkCompiler
*/
public class CompilerComparison {
/**
* JavassistCompiler 优势:
* ✅ 不依赖JDK tools.jar(直接操作字节码)
* ✅ 编译速度快(跳过javac的语法分析/语义分析/代码生成阶段)
* ✅ 内存操作(不需要创建临时.java文件)
* ✅ 灵活(可动态修改类结构,不需要完整源码)
*
* JavassistCompiler 劣势:
* ❌ 复杂语法支持有限(泛型、内部类可能出问题)
* ❌ 调试困难(没有.java文件,无法在源码级别断点)
*
* JdkCompiler 优势:
* ✅ 标准Java语法(任何合法Java代码都能编译)
* ✅ IDE可调试(生成临时.java文件时)
*
* JdkCompiler 劣势:
* ❌ 依赖tools.jar(某些JDK发行版不带)
* ❌ 速度较慢(完整的javac编译流程)
*
* Dubbo选择Javassist的原因:
* - Adaptive类和Wrapper类都是简单类,不需要复杂语法
* - 启动性能是框架级产品的重要指标
* - 跨JDK兼容性(部分环境没有tools.jar)
*/
}
本章总结
本章从AOP和动态编译两个维度揭示了Dubbo的增强机制:
| 技术模块 | 核心实现 | 设计模式 |
|---|---|---|
| AOP | ProtocolFilterWrapper | 装饰器模式(无代理) |
| Filter链构建 | buildInvokerChain | 职责链 + 匿名Invoker |
| 动态编译 | JavassistCompiler.doCompile | 正则拆分 + 字节码构建 |
| Adaptive生成 | createAdaptiveExtensionClass | 代码生成 + 动态编译 |
核心要点:
- Dubbo AOP无运行时代理,通过ExtensionLoader在创建时一次性构建Wrapper链
- Provider端8个内置Filter按order排序形成调用链
- JavassistCompiler通过正则拆分Java源码,逐片段构造CtClass对象