Dubbo—SPI及自适应扩展原理( 六 )
后面会讲到Protocol扩展类都是通过export方法暴露服务 , refer方法引用服务 , 而这两个方法在接口中都标注了@Adaptive注解 , 所以Dubbo为其生成了动态的适配类(这个和Java的动态代理的原理有点像 。 同时我们看到这两个方法中都通过getExtension方法去获取指定的扩展类的实例(这个扩展类名称来自于Invoker(后面会讲)中的url , 因为dubbo是基于url驱动的 , 所有的配置都在url中) 。 这就是Dubbo强大的自适应扩展机制的实现原理 , 我们可以将其运用到我们的项目中去 , 这就是看源码的好处 。 不过还有个问题 , 刚刚在createAdaptiveExtensionClass方法中你一定疑惑compiler是什么 , 它也是调用的getAdaptiveExtension获取适配类 , 这不就进入了死循环么?当然不会 , 首先我们可以去配置文件看看Compiler的扩展类都有哪些:
adaptive=com.alibaba.dubbo.common.compiler.support.AdaptiveCompilerjdk=com.alibaba.dubbo.common.compiler.support.JdkCompilerjavassist=com.alibaba.dubbo.common.compiler.support.JavassistCompiler
有一个AdaptiveCompiler类 , 从名字上我们就能猜到它是一个自定义的适配类了 , 然后在其类上可以看到@Adaptive注解验证我们的猜想 , 那么上文也说了在loadFile方法中会将该类赋值给cachedAdaptiveClass变量缓存 , 然后在createAdaptiveExtension -> getAdaptiveExtensionClass方法中获取并实例化对象 , 所以并不会死循环 , 那么在该类中做了什么呢?
public class AdaptiveCompiler implements Compiler { // 这个是在哪赋值的?private static volatile String DEFAULT_COMPILER;public static void setDefaultCompiler(String compiler) {DEFAULT_COMPILER = compiler;}public Class> compile(String code, ClassLoader classLoader) {Compiler compiler;ExtensionLoader
该适配类会从两个地方获取扩展类 , 先来看看getDefaultExtension:
public T getDefaultExtension() {getExtensionClasses();if(null == cachedDefaultName || cachedDefaultName.length() == 0|| "true".equals(cachedDefaultName)) {return null;}return getExtension(cachedDefaultName);}
cachedDefaultName 这个不陌生吧 , 在loadExtensionClasses方法中赋值的 , 其值为@SPI的值 , 这里就是javassist 。 再看另外一条分支 , 是通过DEFAULT_COMPILER的值去获取的 , 这个变量提供了一个setter方法 , 点过去我们可以看到是在ApplicationConfig类中的setCompiler方法调用的 , 因为该类是配置类实例 , 也就是说可以通过dubbo:application的compiler参数来配置编译器类型 , 查看文档 , 也确实有这个配置参数 。 所以看源码能让我们了解平时项目中配置各个参数的意义 , 从而有针对的选择和配置适当的参数 , 而不是一味的照搬文档就完事 。
三、Dubbo IOC在上文中我们看到injectExtension这样一个方法 , 它是做什么的呢?接下来就详细分析它的作用和实现 。
private T injectExtension(T instance) {try {if (objectFactory != null) {for (Method method : instance.getClass().getMethods()) {if (method.getName().startsWith("set")try {String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";Object object = objectFactory.getExtension(pt, property);if (object != null) {method.invoke(instance, object);}} catch (Exception e) {logger.error("fail to inject via method " + method.getName()+ " of interface " + type.getName() + ": " + e.getMessage(), e);}}}}} catch (Exception e) {logger.error(e.getMessage(), e);}return instance;}
推荐阅读
- Linspire 10 Beta版发布 还记得20年前的Lindows吗?
- CES 2021:JBL发布新款耳机 支持自适应噪声消除功能
- 宏碁推Chromebook Spin 514:首配Ryzen 3000 C芯片
- 三星自适应HDR10+调节功能将考虑环境光因素
- 苹果申请新专利:自适应环境光,或用于智能眼镜Apple Glass
- 本田的黑科技又来了 摩托车自动驾驶专利被曝光
- Spin计划为共享滑板车加装传感器 遏制客户的不当停车和骑行行为
- 分布式天花板?阿里百万架构师的ZK+Dubbo笔记,颠覆认知
- 中国工程院院士郭剑波:适应高比例新能源电力系统,电源电网都要改变
- 《今日简史》:人工智能时代,未来10年这样学习才能适应发展