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;}