扩展点加载机制
只有标有@SPI注解的接口类才会查找扩展点的实现,依次从下面这三个路径读取扩展点文件:META-INF/dubbo/internal 、META-INF/dubbo/ 、META-INF/services/,其中dubbo内部实现的各种扩展文件都放在META-INF/dubbo/internal目录下面。
getExtensionLoader(Class<T>type)方法:调用此静态方法获得ExtensionLoader对象实例,该类对于每个Class对象创建一个ExtensionLoader实例。
1)检查type接口类是否使用了@SPI注解,只有使用了该注解的接口类才会查找扩展点实现类;否则抛异常。
2)从全局静态变量ExtensionLoader.EXTENSION_LOADERS:ConcurrentHashMap<Class<?>,ExtensionLoader<?>>中查找是否已经存在扩展点的ExtensionLoader对象,若没有则调用私有构造函数ExtensionLoader(Class<?> type)。
3)在该私有构造函数中,完成ExtensionLoader对象的两个成员变量的赋值,第一,type:Class变量;第二,objectFactory:ExtensionFactory变量,若type为ExtensionFactory.class,则objectFactory=null,否则通过ExtensionLoader获取ExtensionFactory.class的扩展点实现类。代码如下:
一、getAdaptiveExtension()方法:获取扩展点实现类的适配器类实例。从ExtensionLoader.cachedAdaptiveInstance变量中获取,若为空,则调用createAdaptiveExtension方法创建适配器类的实例,并将适配器类的实例缓存到cachedAdaptiveInstance变量中。
createAdaptiveExtension方法:完成适配器类的实例化并对适配器类的实例对象中是扩展点接口的成员变量初始化值。
1)调用getAdaptiveExtensionClass方法,创建适配器类的class对象;
2)调用Class.newInstance方法完成class对象的实例化;
3)调用injectExtension方法完成实例化对象中成员变量的初始化工作。
getAdaptiveExtensionClass方法:创建扩展点实现类的适配器类。
1)调用getExtensionClasses方法,获取扩展点的所有实现类;
2)扩展点的实现类中已经有使用了@Adaptive注解的类,则该类即作为适配器类,即ExtensionLoader.cachedAdaptiveClass 变量值;
3)若没有实现类使用@Adaptive注解,则动态生成一个适配器类,具体的实现调用createAdaptiveExtensionClass方法中完成。
getExtensionClasses方法:获取扩展点实现类的Map对象。
1)检查缓存ExtensionLoader.cachedClasses 变量中是否有值,若有则直接返回;
2)若没有缓存,则调用loadExtensionClasses方法获取Map对象,并存入ExtensionLoader.cachedClasses变量中。
loadExtensionClasses方法:加载扩展点的实现类。
1)获取ExtensionLoader.type参数值的类的SPI注解,获取该注解的value值,若该值不为空且只有一个值的话,则保存ExtensionLoader.cachedDefaultName 对象,作为默认实现类使用;若为空则表示没有指定默认的实现类;但SPI注解的value值一定不能设置多个。
2)调用loadFile方法解析以ExtensionLoader.type的类名来命名的文件内容,并返回Map对象,该对象的每个K-V即为文件中的一行内容,key=类简称,value=class对象;
loadFile方法:逐行读取以ExtensionLoader.type参数值的类名来命名的文件内容;ExtensionLoader.type的值是在ExtensionLoader.getExtensionLoader方法调用时传入的。以ExtensionFactory为例,文件内容的格式如下。
对每行的解析工作如下:
1)等号右边为实现类的类名。等号左边为该类的简称;若只写类名,则以一定的规则来获取类的简称,具体见下面的步骤实现;左边的简称也可以是以逗号分隔的多个简称;
2)对等号右边的类使用Class.forName方法创建class对象,后续对该class对象进行操作;
3)该class对象必须实现了ExtensionLoader.type参数指定的接口;
4)该class对象是否使用了@Adaptive注解,若使用了则将该class对象保存到ExtensionLoader.cachedAdaptiveClass 变量中,在每个文件中的所有实现类最多只能有一个类使用了@Adaptive注解;该行解析结束,继续下一行;若没有使用@Adaptive注解的类,则进行下面的解析步骤;
5)该class对象是否有ExtensionLoader.type参数的构造函数,若有则表示可以进行封装,将该class存入ExtensionLoader.cachedWrapperClasses 变量中,该行解析结束,继续下一行的解析;例如Protocol接口的扩展点文件中的ProtocolFilterWrapper类的记录,该实现类有一个Protocol参数的构造函数,故是在创建Protocol的扩展点实现类的实例时用该类封装一层,若没有,则继续下面的解析步骤;
6)若等号左边为空或者该行没有等号,则坚持该class对象是否使用了@Extension注解,若使用了则取该注解的value值作为该class对象的简称;若没有使用@Extension注解,但实现类的类名是以接口名结尾的,则取类名的前部分为简称;但若不是以接口名结尾的类名,则以类名为该类的简称;
7)检查class对象是否使用了@Activate注解;若使用则获取该注解,并存入ExtensionLoader.cachedActivates对象中,key为类的简称,若有多个简称则取第一个;
8)遍历所有的类简称,将class对象和每个类简称存入ExtensionLoader.cachedNames对象中,其中key=class对象,value=类简称;将每个类简称和class对象存入Map对象并返回,key=类简称,value=class对象;
createAdaptiveExtensionClass方法:该方法在运行时动态创建适配器类。
1)动态生成适配器类的代码,下面列出了部分接口的动态适配器类的代码:CacheFactory、Cluster、ConfiguratorFactory、Dispatcher、HttpBinder、MonitorFactory、Protocol、ProxyFactory、RegistryFactory、RouterFactory、ThreadPool、Transporter、Validation、ZookeeperTransporter,具体代码见《附件一》。在生成适配器类时,若接口中没有声明带@Adaptive注解的方法,则不生成适配器类,若有,则在生成适配器类时,对带注解的方法重写;
2)编译适配器类代码,创建Class对象。编译器也是通过ExtensionLoader类来动态扩展的,默认选择JavassistCompiler编译器。
injectExtension方法:对于非ExtensionFactory.Class对象,利用ExtensionFactory的扩展实现类的对象获取成员变量的初始化值,实现代码如下:
1)获取公有的set方法,解析出成员变量的名称。
2)调用ExtensionFactory.getExtension方法获取成员变量的值。
3)通过反射的方式调用set方法完成成员变量值的注入。
ExtensionFactory.getExtension方法:在ExtensionFactory的文件中,包含了AdaptiveExtensionFactory类,该类使用了@Adaptive注解,所以ExtensionFactory接口的适配器为AdaptiveExtensionFactory类,故调用的是该适配器类的getExtension方法。
1)在该方法中遍历ExtensionFactory扩展文件中的所有ExtensionFactory对象的getExtension方法,代码如下:
2)目前有SpiExtensionFactory和SpringExtensionFactory两种;第一,对于SpiExtensionFactory.getExtension方法,根据成员变量的类型从扩展点中加载该对象,代码如下:
第二,对于SpringExtensionFactory.getExtension 方法,从Spring的上下文中获取该成员变量的Bean对象,代码如下:
二、getExtension(String name)方法:返回指定名字的扩展类实例,
1)如果指定名字的扩展类不存在,则抛异常。
2)如果指定的名字为“true”,则返回默认的实现类实例,即name= cachedDefaultName;
3)从ExtensionLoader.cachedInstances:ConcurrentHashMap变量中获取该name的实例;
4)若Map中没有该name的实例,则调用createExtension方法创建该实例,并保存到缓存中。
createExtension(String name)方法:创建扩展点实现类的实例对象。
1)调用getExtensionClasses方法,获取type参数的文件内容;并从Map对象中获取name的Class对象,若没有则抛异常;
2)从全局变量ExtensionLoader.EXTENSION_INSTANCES:ConcurrentMap<Class<?>, Object> 中获取该class的实例,若没有,则创建该Class对象的实例,并缓存到上面的Map变量中;
3)调用injectExtension方法完成成员变量的初始化值注入工作;
4)遍历cachedWrapperClasses变量,利用以type接口为参数的构造函数创建每个封装类,故对扩展类的实例进行了封装。并调用injectExtension方法对封装类的成员变量进行初始化工作;
5)返回的实例是经过封装之后的实例对象。
三、getActivateExtension(URL url, String key, String group)方法:主要是获取当前扩展的所有可自动激活的实现类的实例列表exts:List<T>。
1)调用getExtensionClasses方法,加载当前扩展接口的所有实现,会获取到当前Extension中所有@Active实现,赋值给cachedActivates变量;
2)遍历cachedActivates集合,检查集合中每个类中@Active注解的group值是否与入参的值一致,若一致,则加入exts列表中;
3)使用ActivateComparator对exts列表的集合进行排序,排序的依据主要是@Active注解的before、after、order的值来定;
4)检查中是否有key参数值,若有则将这些参数值的类加入到exts列表中;例如在服务暴露时,key=“service.filter”,则从URL中获取该参数的值,该值是在<dubbo:service>标签的filter属性中配置的服务提供方远程调用过程拦截器名称,多个名称用逗号分隔;
5)最后将所有的exts列表返回