Dubbo源码学习笔记 之 扩展机制与ExtensionLoader类
dubbo的代码很久之前看过一遍,个人比较懒,没有做笔记总结,很多都忘了。最近抽时间仔细学习了下源码,记录总结下,加深印象。
环境:
源码版本: 2.7.3-SNAPSHOT
IDE: idea Intelij
1. 扩展机制 与 ExtensionLoader 类
Dubbo 采用 的微内核+扩展的优秀设计,扩展点设计借鉴了JDK 的ServiceLoader 机制, 核心实现落在 ExtensionLoader.class ,理解这个类,对读懂、调试代码非常关键。
ExtensiionLoader 类的成员变量如下:
// ===============基础数据=============== private String cachedDefaultName; //SPI 默认扩展名称 private final Class<?> type; //当前加载的SPI class 类型 private final ExtensionFactory objectFactory; //对象工厂的SPI 的扩展, 用于对Extension 注入属性(set方法对象) // =========Class 缓存========= private volatile Class<?> cachedAdaptiveClass = null; private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>(); private Set<Class<?>> cachedWrapperClasses; //Warp扩展 class集合。 如果一个扩展的构造函数参数类型为当前扩展,则这个扩展为Wrap型 // ==========Instance 缓存================= private final Holder<Object> cachedAdaptiveInstance = new Holder<>(); //Adaptive 实例缓存 private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>(); //生成的扩展实例缓存 private final Map<String, Object> cachedActivates = new ConcurrentHashMap<>(); //Activate 扩展实例缓存 // =============运行时产生内容============= private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<>(); //缓存的扩展点Class-名称 映射 private volatile Throwable createAdaptiveInstanceError; private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<>(); private ExtensionLoader(Class<?> type) { this.type = type; //每个ExtensionLoader (除了ExtensionFactory)都需要一个 factory, 依然采用扩展机制加载 objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); }
将成员变量分成基础数据, Class缓存,Instance缓存, 运行时产生的其他数据四种。
当执行 loadExtensionClasses() 方法,遍历所有的扩展实现后,在loadClass()方法里,
一个扩展必会被 划分为adaptive、普通实现、wrap 扩展中的一种:
1. Adaptive扩展 ,在class上面带有Adaptive注解,至多1个(如没有,在调用getAdaptiveExtension()时自动生成一个), 例如:AdaptiveExtensionFactory 类
2. 普通扩展 , 扩展点的具体实现,例如Protocol 扩展的 DubboProtocol 扩展。
3. wrap 扩展, 该类型的扩展,有个该扩展点的构造函数,例如 ProtocolFilterWrapper 为Protocol的扩展,有个 构造函数,需要Protocol类型的参数。 wrap扩展,是对普通扩展的包装,当生成普通扩展时,都会循环一遍wrap class,全部包装一遍。
2. 重要方法:
ExtensionLoader 有2个重要的方法:getAdaptiveExtension()与 getActivateExtension()
getAdaptiveExtension :
adaptive扩展, 是一个包装(代理)类,会根据运行时传入url里面的key-value 值,确定最终调用的实际扩展。
内部逻辑如下:
如有成员变量 adaptiveClass 有值,则直接用class.newInstance() 一个实例出来,
如果 无值,则 用String 构造一个adaptiveClass 的源码,用complier 实时编译,生成adaptive 实例。
getActivateExtension:
activate 扩展,是一个有条件的扩展,当分组 && 值满足条件时,才会被加载到。
例如调用Invokcation的 Fitler,Group分为 provider 与consumer, 当Filter 分组取值为privider时,会被server 端构建。
//group 为provider,仅用于发布服务 //value 有值,需要在配置里面, accesslog 属性配置项有值 @Activate(group = PROVIDER, value = ACCESS_LOG_KEY) public class AccessLogFilter implements Filter {
3. 扩展的实例化
在dubbo里面,扩展一般都是无参构造函数,除了wrap扩展,是有个本扩展点的构造函数。
扩展点实例化后,会注入属性。 遍历set开头的方法,查找方法的参数类型, 然后通过objectFactory 去获取对应类型的对象,完成注入。
属性注入,在ExchangeServer、Transporter 里面比较容易看到,在最开始Debug跟踪源码的时候,经常不知道这个属性是什么时候来的,感觉莫名其妙。
以上几个点,基本就是ExtensionLoader方法里面比较关键的部分,弄清楚以上几个点,对于微内核的运行机制,就能很清楚了。 后续就是流程组装了。
posted on 2019-06-20 14:44 qingcaolin 阅读(287) 评论(0) 编辑 收藏 举报