ExtensionLoader 几个重要方法:
1.getExtensionLoader(Class type);
根据 class 从缓存中获取可用的ExtensionLoader 工厂,如果没有则创建新实例( new ExtensionLoader(Class type))并放入缓存中
2.getAdaptiveExtension(); 获取AdaptiveExtension 实例 【包含被@Adaptive注解的类实例和动态生成的代理类 ***$Adapive】
3.createAdaptiveExtension(); 实例化 AdaptiveExtension 【包含 创建对应AdaptiveExtension初始化和对应属性注入】
4.getAdaptiveExtensionClass(); 获取当前 Class<?> type 对应的AdaptiveExtension.class 【包含定义好的被 @Adaptive 注解的 class 和动态生成的 InterfaceName$Adaptive 类】
其中在动态创建AdaptiveClass时【
方法 createAdaptiveExtensionClassCode】会判断当前type接口中是否有 @Adaptive 标注的方法,有才会生成代理类,没有则会报错。
如
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
如接口 com.alibaba.dubbo.rpc.Protocol
最后会根据接口方法生成代理类,最后使用javassist编译成class字节码
代理类如下:
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
5.getExtensionClasses() 获取当前 Class<?> type 对应的所有ExtensionClass;
6.loadExtensionClasses(); 载入所有符合 当前 Class<?> type 所有 ExtensionClass 【默认根据 AppClassLoader 获取 classpath 下 META-INF/dubbo/internal/ , META-INF/dubbo/ ,META-INF/services/ 三个目录下的所有SPI 文件配置的Class】
7.loadFile(Map<String, Class<?>> extensionClasses, String dir) 加载对应目录文件,根据属性value 获取对应的Class 最终行成 Map<String, Class<?>> 形式map存放在当前ExtensionLoader中;同时
初始化过程中遇到被标注为 @Adaptive 的类 设置为当前 ExtensionLoader 的AdaptiveClass,如果遇到Class需要构造函数为 Constructor(Class<?> type),则设置为当前 Class<?> type 的 Wrapper Class
8.createAdaptiveExtensionClass(); 创建动态代理类 Class<?> type .simpleName()$Adaptive 如当前type = com.alibaba.protocol.Protocol 则最终生成的proxy 为 Proxy$Adaptive.class
9.createAdaptiveExtensionClassCode(); 根据Class<?> type 生成 type.getSimpleName()$Adaptive 的java类,并使用 javassist 编译生成动态代理类。
生成的代理类会内部关键代码:
defaultExtName = cacheDefaultName;//cacheDefaultName 为 在获取对应的 Class<?> type 所有ExtensionClass时 根据 @SPI(
value
="****") 中设置的默认值 如 @
SPI
(
value
="dubbo") 则 cacheDefaultName = dubbo;
String extName = url.getProtocol() == null ? defaultExtName : url.getProtocol() '
T instance = ExtensionLoader.getExtensionLoader(Class<T> type).getExtension(extName);
return instance.method();
因此在后续所有业务逻辑中调试代码时发现自动先跳入到 url.getProtocol获取protocol后就能获取到Extension实例;
主要调用过程:
10.getExtention(String name) 根据给定的类型获取扩展点实例,而且是线程安全方式,使用 holder来保存实际的扩展点实例句柄
11.createExtension(name) 创建扩展点实例
创建扩展点实例逻辑分4步:
1).首先根据名称来获取扩展点 Class ,不存在则抛出异常
2).从实例缓存中获取实例 EXTENSION_INSTANCES -> Map<Class,Object> 不存在根据Class.getInstance() 获取
3).设置实例中需要属性注入的类型
4).如果扩展点有wrapper型的实现,则返回instance包装类 wrapper (wrapper类 可查看 第7点 loadFile ),因此会发现后续调用getExtension获取扩展实例时返回的是包装类(wrapper类)
>>>>>>>>>>
举例: ReferenceConfig 中 private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
proxyFactory 为创建消费服务代理ref的工程类
ref = createProxy(map);
createProxy(map){
return proxyFactory.getProxy(invoker);
}
而 ProxyFactory 默认@
SPI
(
value
="javassist") 为javassist,由 META_INF/dubbo/internal/com.alibaba.dubbo.rpc.ProxyFactory 内容
stub=com.alibaba.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper
jdk=com.alibaba.dubbo.rpc.proxy.jdk.JdkProxyFactory
javassist=com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory
可知代理创建工厂应该为 JavassistProxyFactory
但是因为StubProcyFactoryWrapper 也同样实现 ProxyFactory,根据loadFile方法在初始化扩展点时会将包装类初始化并放入cacheWrapperClasses中缓存,而getExtention方法在获取扩展点实例时如果发现当前接口实现有相关扩展包装类,则返回包装类可知,实际 proxyFactory 为 包含有 javassistProxyFactory 的 StubProcyFactoryWrapper
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<