dubbo源码之-ExtensionInjector

news/2024/11/17 20:44:57/

dubbo源码之-ExtensionInjector

  • 概述
  • 源码入口
  • Extension 是如何获取到?
  • SpiExtensionInjector

概述

其实ExtensionInjector 非常简单, 我们知道dubbo有ioc注入的功能, 是靠的set方法注入,对应的底层源码主要是ExtensionInjector
如果不知道dubbo的ioc 参考 dubbo源码阅读之-java spi, dubbo spi 和 Spring spi 到底有啥区别
在这里插入图片描述

源码入口

总结:
1.set方法注入条件:set开头,参数只有一个,public修饰
2.set方法上没有使用 DisableInject 注解
3.set 方法是在ScopeModelAware 系列中声明的也不能注入

org.apache.dubbo.common.extension.ExtensionLoader#injectExtensionprivate T injectExtension(T instance) {if (injector == null) {return instance;}try {//获取当前对象的当前类的所有方法for (Method method : instance.getClass().getMethods()) {//是否为set方法 不是的话则跳过,在这里合法的set方法满足3个条件://set开头,参数只有一个,public修饰if (!isSetter(method)) {continue;}/*** Check {@link DisableInject} to see if we need auto-injection for this property*///方法上面是否有注解DisableInject修饰,这种情况也直接跳过if (method.isAnnotationPresent(DisableInject.class)) {continue;}// When spiXXX implements ScopeModelAware, ExtensionAccessorAware,// the setXXX of ScopeModelAware and ExtensionAccessorAware does not need to be injectedif (method.getDeclaringClass() == ScopeModelAware.class) {continue;}if (instance instanceof ScopeModelAware || instance instanceof ExtensionAccessorAware) {if (ignoredInjectMethodsDesc.contains(ReflectUtils.getDesc(method))) {continue;}}Class<?> pt = method.getParameterTypes()[0];//方法的参数如果是原生类型也跳过if (ReflectUtils.isPrimitives(pt)) {continue;}try {//获取set方法对应的成员变量如setProtocol 属性为protocolString property = getSetterProperty(method);//根据参数类型如Protocol和属性名字如protocol获取应该注入的对象Object object = injector.getInstance(pt, property);if (object != null) {//执行对应对象和对应参数的这个方法method.invoke(instance, object);}} catch (Exception e) {logger.error(COMMON_ERROR_LOAD_EXTENSION, "", "","Failed to inject via method " + method.getName() + " of interface " + type.getName() + ": " + e.getMessage(),e);}}} catch (Exception e) {logger.error(COMMON_ERROR_LOAD_EXTENSION, "", "", e.getMessage(), e);}return instance;}

Extension 是如何获取到?

这一行的关键是需要知道injector的实例

Object object = injector.getInstance(pt, property);

在ExtensionLoader中 是一个属性, 在构造方法中进行的初始化
private final ExtensionInjector injector;

 //如果当前扩展类型为扩展注入器类型则设置当前注入器变量为空,否则的话获取一个扩展注入器扩展对象//1)这里有个type为空的判断,普通的扩展类型肯定不是ExtensionInjector类型 这里必定会为每个非扩展注入ExtensionInjector类型创建一个ExtensionInjector类型的扩展对象,
//2) 这里代码会走extensionDirector.getExtensionLoader(ExtensionInjector.class),这个代码会创建一个为ExtensionInjector扩展对象的加载器对象ExtensionLoader
//3) getAdaptiveExtension() 这个方法就是通过扩展加载器获取具体的扩展对象的方法我们会详细说
this.injector = (type == ExtensionInjector.class ?null : extensionDirector.getExtensionLoader(ExtensionInjector.class).getAdaptiveExtension());

根据上面的代码可以知道 injector 是 ExtensionInjector 一个实现类型有Adaptive注解的实现类,从上uml类图上可以知道是:AdaptiveExtensionInjector

initialize 方法在ExtensionLoader的初始化的时候调用,也就是说获取到ExtensionInjector的所有非自适应的实现类

@Overridepublic void initialize() throws IllegalStateException {ExtensionLoader<ExtensionInjector> loader = extensionAccessor.getExtensionLoader(ExtensionInjector.class);injectors = loader.getSupportedExtensions().stream().map(loader::getExtension).collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));//collectingAndThen 去重操作}

从中我们可以看到从
//ScopeBeanExtensionInjector
//SpiExtensionInjector
//SpringExtensionInjector
三者中获取实例,只获取第一个非空实例

   //可以看到上面代码按扩展注入器顺序来遍历的第一个找到的对象就直接返回了,//这个AdaptiveExtensionInjector在初始化的时候会获取所有的ExtensionInjector的扩展,非自适应的,它本身自适应的扩展,// 这里会获取非自适应的扩展列表一共有3个按顺序为://ScopeBeanExtensionInjector//SpiExtensionInjector//SpringExtensionInjector@Overridepublic <T> T getInstance(final Class<T> type, final String name) {//遍历所有的扩展注入器,如果可以获取到扩展对象则直接返回return injectors.stream().map(injector -> injector.getInstance(type, name)).filter(Objects::nonNull).findFirst().orElse(null);}

SpiExtensionInjector

其他的不做过多解释 ,今天只写一下这个SpiExtensionInjector吧

 @Overridepublic <T> T getInstance(final Class<T> type, final String name) {//如果是一个标准的被@SPI注解修饰的扩展接口则满足条件if (!type.isInterface() || !type.isAnnotationPresent(SPI.class)) {return null;}//使用扩展访问器来获取对应类型的扩展加载器ExtensionLoader<T> loader = extensionAccessor.getExtensionLoader(type);if (loader == null) {return null;}//使用对应类型的扩展加载器来加载自适应扩展 这个加载的扩展可以参考4.4.6小节if (!loader.getSupportedExtensions().isEmpty()) {return loader.getAdaptiveExtension();}return null;}

http://www.ppmy.cn/news/413199.html

相关文章

怀旧服显示服务器已满,魔兽世界怀旧服还未开启就已人满为患

根据暴雪依据服务器预约名称的情况分析&#xff0c;有些服务区已经人满为患。 在新的博客中&#xff0c;魔兽世界社区经理Randy Jordan 说到&#xff0c;根据暴雪本月开放的魔兽世界怀旧服中人物名称预约情况&#xff0c;”Herod 服务器看起来已经人满为患。”实际上如今魔兽世…

怀旧服服务器一般什么时候维护,魔兽世界怀旧服9月16日重启维护结束时间 9.16怀旧服登录不了游戏解决方法_蚕豆网新闻...

今天&#xff0c;也就是9月16日。《魔兽世界怀旧服》终于开启了重启维护&#xff0c;官方已经发出了公告&#xff0c;预计3小时的重启维护时间&#xff0c;很多玩家还不知道这个消息&#xff0c;小编带来了最新的官方咨询&#xff0c;感兴趣就来看看吧。 为了保证服务器的稳定运…

qq登录无法连接服务器未响应,win7登录qq提示腾讯qq未响应的解决方法

有许多 win7 32位 系统的用户反馈&#xff0c;最近在登录qq的时候非常卡&#xff0c;经常出现未响应的情况&#xff0c;会突然弹出“腾讯qq未响应”的提示窗口&#xff0c;遇到这种情况我们该怎么办呢&#xff1f;我们可以对qq进行一些清理&#xff0c;下面由PConline小编给大家…

qq登录无法连接服务器未响应,Windows7系统中登录QQ时提示腾讯qq未响应的解决方法...

最近有用户在登录QQ的时候非常的卡&#xff0c;经常出现未响应的情况&#xff0c;还会突然弹出“腾讯qq未响应”的提示窗口&#xff0c;那么在遇到这样的情况时我们怎么来处理呢&#xff1f;一起来看看吧&#xff01; 具体方法如下: 1、登录qq后&#xff0c;点击下方的“系统设…

wow 正在登陆服务器 就未响应,魔兽世界9.0画面卡住未响应解决办法

魔兽世界9.0画面卡住未响应解决办法启用旧组件Direct play&#xff0c;这个组件在Win10 Win7都有&#xff0c;相比起Win7&#xff0c;Win10提供的Direct 少了一些文件&#xff0c;导致游戏运行卡顿&#xff0c;关闭WIN10中的exploit protection。 详细答案&#xff1a; 1.启用旧…

玩什么java总是未响应,游戏经常未响应怎么办

游戏经常未响应怎么办 在玩游戏时是否出现过电脑未响应的情况&#xff0c;本教程为大家提供一些解决方法&#xff0c;希望对大家有帮助。 方法/步骤 情况一&#xff1a;内存使用率过低&#xff0c;电脑工作一段时间之后物理内存中将累积不少数据&#xff0c;假如物理内存容量偏…

魔兽服务器不显示pvp,《魔兽世界怎么关掉pvp》,魔兽世界 PVP服务器 如何关闭PVP?...

魔兽世界 PVP服务器 如何关闭PVP?问题说明&#xff1a;很烦人 如何关闭PVP呢&#xff1f; 不想打野外PVP。在PVP服务器中。。野外不能关闭PVP功能。。只有在自己的领地或者沙城PVP才可以关闭。。在争夺中的领地PVP不能关闭。。。。 PVE的服务器中。。你自己随时可... 魔兽世界…

wow服务器合并信息,《魔兽世界》台服合并部分服务器_网络游戏魔兽世界_新浪游戏_新浪网...

以下是来自中国台湾地区的消息: 《魔兽世界》部分服务器将于5月25日至5月27日进行合并&#xff0c;预计会把“水晶之刺、死亡之翼、大地之怒、血顶部族、羽月、龙骨荒野、艾格拉玛、恶魔之”等 8 台 PVP服务器合并为4台&#xff0c;以求联盟与部落阵营的人数平衡。 服务器补偿办…