前言
dubbo 实现机制的核心在于其签到好处的使用了各种设计模式,以及其设计的SPI 机制,从而实现了动态的获取一个接口的具体的实现类,但是要了解SPI 首先要了解 @SPI 注解,以及自适应拓展时候的用到的@Adaptive注解
1.@SPI的用法
被注解修饰的类或者接口上 标注@SPI 注解代表当前类为拓展类,如果@SPI(value)有指定value则,这个动态拓展类的默认实现类就是 这个value 对应在 META-INF/dubbo,META-INF/dubbo/internal,META-INF/service 目录下定义 当前类全路径对应的文件,文件中的key=value ,这 key对应值就是默认的实现类
2. @Adaptive 的用法
在实际应用场景中,一个扩展接口往往会有多种实现类,因为Dubbo是基于URL驱动,所以在运行时,通过传入URL中的某些参数来动态控制具体实现,这便是Dubbo的扩展点自适应特性。
在Dubbo中,@Adaptive一般用来修饰类和接口方法,在整个Dubbo框架中,只有少数几个地方使用在类级别上,如AdaptiveExtensionFactory和AdaptiveCompiler,其余都标注在方法上。
1.当@Adaptive 修饰类的方法时候,dubbo 会动态生成代理类,来实现该方法,然后底层还是调用真实的实现类对应的方法
2.当@Adaptive 修饰类的时候,dubbo 不会生成代理类,但是可以找到其对应实现的接口,找到对应默认的实现类,以及非默认实现类,具体调用那个使情况而定。
3.对比方法级别,类级别省略了生成动态代理类的过程,由指定类决定具体实现,另外对于同一个扩展点,类级别的Adaptive只能有一个。
例子可以参考:https://blog.csdn.net/u011212394/article/details/102762197
3.自适应拓展类,动态类代码生成
1.自适应头站类,跟踪getAdaptiveExtension 方法代码
2.进入方法内部getAdaptiveExtension
3.进入到createAdaptiveExtension方法
4.继续跟踪getAdaptiveExtensionClass,我们会看到两个关键的方法
1.getExtensionClasses 这个方法是 、从 ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension() 指定的类ProxyFactory 解析其SPI 注解,并且将当前默认实现生成动态代码的类设置为 SPI(“xx”)指定的xx类,并且在当前项目的resource目录下 的 META-INF/dubbo/,META-INF/dubbo/internal/,META-INF/services/ 这三个文件目录下找 找文件名称为ProxyFactory全路径的文件,然后在 这个文件中找到 key 为 xx 的对应的类作为实现类。
2.然后看看具体的类createAdaptiveExtensionClass ,如果对应的ProxyFactory 类中有方法被@Adaptive 修饰,则在 createAdaptiveExtensionClassCode 方法中会生成动态的 代理类字符串,然后利用同样的方法生成 Compiler编译类,让后将 刚生成的动态代理类字符串 编译成类。
4.具体案例刨析
1.我们这边以这个为例 获取 ProxyFactory 类的自适应拓展类。
2.我们更加 ProxyFactory 类的全路径拓展名,并且在当前项目的resource目录下 的 META-INF/dubbo/,META-INF/dubbo/internal/,META-INF/services/ 这三个文件目录下找 找文件名称为ProxyFactory全路径的文件,然后在 这个文件中找到 key 为 xx 的对应的类作为实现类。
3.由于当前ProxyFactory 类的方法有被@Adaptive注解 修饰所以要动态生成 代理类字符串然后编译成类对象获取其实例
4. 也就是说 我们定义的 proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(),其实是一个动态代理类,当我们调用其 对应的 方法时候,其实是调用的 SPI 找到具体实现类(JavassistProxyFactory)中的方法