承上
上篇分析到了 injectExtension
,其中 objectFactory
需要详细分析
Object object = objectFactory.getExtension(pt, property);
objectFactory
是在用私有构造方法初始化的 ExtensionFactory
的自适应实现类。
// 如果是扩展工厂类型 则返回 null
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
即最重要的是这一句:ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()
和简单使用方法对比一下,我们会发现它调用的是 getAdaptiveExtension
方法
第一层 getAdaptiveExtension
分析
getAdaptiveExtension
主要的作用是 获取
// 获得扩展实例
public T getAdaptiveExtension() {
// 先从本地缓存中查找
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {
if (createAdaptiveInstanceError == null) {
synchronized (cachedAdaptiveInstance) {
// 解决多线程情况下 指令重排的问题 参数使用 volatile 修饰
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
// 创建适应的实例
instance = createAdaptiveExtension();
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException ...
}
}
}
} else {
throw new IllegalStateException ...
}
}
return (T) instance;
}
第二层 createAdaptiveExtension
分析
createAdaptiveExtension
和上文分析的 createExtension
作用相似,但是实现有很大区别,这个方法标示着 Dubbo 自己扩展的 SPI 机制增加的对扩展点自适应的支持。
第三层 getAdaptiveExtensionClass
分析
getAdaptiveExtensionClass
的主要作用的是先从缓存中加载,如果从未加载过则再调用方法加载
第四层 createAdaptiveExtensionClass
分析
创建一个扩展点的代理,将扩展的选择从 Dubbo 启动时,延迟到 RPC 调用时。非常有意思的是实现动态编译的 Compiler
也使用的插件的方式。
private Class<?> createAdaptiveExtensionClass() {
// 生成 SPI 的自适应实现类的 .java 代码
// 先生成Java源代码,然后编译,加载到jvm中。通过这种方式,可以更好的控制生成的Java类。而且这样也不用care各个字节码生成框架的api
String code = createAdaptiveExtensionClassCode();
ClassLoader classLoader = findClassLoader();
// 选择一个编译框架
org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
// 编译 Java 源码
return compiler.compile(code, classLoader);
}
第五层 createAdaptiveExtensionClassCode
分析
这个主要时生成 SPI 自适应实现类的 .java 代码,最重要也是相对比较复杂的,耐心看完这一点就离成功不远了,刚把得!
Compiler
解析
Dubbo 会自动为我们创建一个,默认使用 Javaassist
@SPI("javassist")
public interface Compiler {
// 你会发现 这个方法上没有 @Adaptive 注解,根据上文分析应该会报错吧?
// 不用担心不会,它的dubbo源码中唯二 实现类上有 @Adaptive 的,走不到那段生成代码的逻辑
// 另一个是 ExtensionFactory
Class<?> compile(String code, ClassLoader classLoader);
}
自适应实现
总结
getActivateExtension
就不再分析了。另外实现 AOP
功能的 Wrapper 类也不再详细分析了。
理解了 SPI
的实现能够帮助我们分析 Dubbo
源码的实现。不就是各个插件组装嘛,对吧 :)
- 扩展点自动包装
- 由
wrapperClass.getConstructor(type).newInstance(instance)
实现
- 自动包装扩展点的 Wrapper 类
- 根据代码分析 只要扩展点有拷贝构造函数,则判定为扩展点 Wrapper 类。
- 新加的 Wrapper 在所有的扩展点上添加了逻辑,有些类似 AOP,即 Wrapper 代理了扩展点。
- 扩展点自动装配
- 由
injectExtension
实现
- ExtensionLoader 通过扫描扩展点实现类的所有 setter 方法来判定其成员。
- 自动注入依赖的扩展点,实现 IoC
- 扩展点自适应
- 由
getAdaptiveExtension
实现
- ExtensionLoader 注入的依赖扩展点是一个 Adaptive 实例,直到扩展点方法执行时才决定调用是一个扩展点实现。
- Dubbo 使用 URL 对象(包含了 Key-Value)传递配置信息。
- 扩展点自动激活
- 由
getActivateExtension
实现
- 同时加载多个实现,可以用自动激活来简化配置
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于