Dubbo-Dubbo SPI 依赖注入
Posted 汪小哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dubbo-Dubbo SPI 依赖注入相关的知识,希望对你有一定的参考价值。
Dubbo SPI 依赖注入
一、何为依赖注入
如果作为Java后端开发、一定是熟悉使用spring这个强大的IOC工具,依赖注入就一定是非常的了解的!在Dubbo自动生成SPI的扩展实例的时候也会发生依赖注入的场景,举一个具体的例子。
1、例子
动态获取配置中心,这里getDynamicConfiguration()并没有去处理设置 ZookeeperTransporter,怎么处理进去的?
DynamicConfigurationFactory factories = ExtensionLoader
.getExtensionLoader(DynamicConfigurationFactory.class)
.getExtension(url.getProtocol());
DynamicConfiguration configuration = factories.getDynamicConfiguration(url);
2、DynamicConfigurationFactory 具体代码
2.1 SPI 接口
/**
* 默认是什么都没有实现的
*/
@SPI("nop")
public interface DynamicConfigurationFactory
/**
* 根据SPI动态获取配置中心
* @param url
* @return
*/
DynamicConfiguration getDynamicConfiguration(URL url);
2.2 SPI的实现类
/**
* 动态配置中心 http://dubbo.apache.org/zh-cn/docs/user/configuration/config-center.html
*/
public class ZookeeperDynamicConfigurationFactory extends AbstractDynamicConfigurationFactory
/**
* Zookeeper 也是动态生成的扩展
*/
private ZookeeperTransporter zookeeperTransporter;
public void setZookeeperTransporter(ZookeeperTransporter zookeeperTransporter)
this.zookeeperTransporter = zookeeperTransporter;
@Override
protected DynamicConfiguration createDynamicConfiguration(URL url)
return new ZookeeperDynamicConfiguration(url, zookeeperTransporter);
2.3 ZookeeperDynamicConfigurationFactory 的依赖也是一个SPI
@SPI("curator")
public interface ZookeeperTransporter
@Adaptive(Constants.CLIENT_KEY, Constants.TRANSPORTER_KEY)
ZookeeperClient connect(URL url);
3、注入详情
根据之前的了解,获取某个具体的扩展Class之后,反射完成成都需要进行依赖注入的。
org.apache.dubbo.common.extension.ExtensionLoader#injectExtension
获取这个方法的第一个参数Class、获取方法的名称 去掉set 必须为标准的,然后根据ExtensionFactory 扩展工厂进行获取具体的实例的信息进行注入。
/**
* 信息 依赖注入:内部SPI ACTIVE 的依赖需要 ExtensionFactory 工厂能够处理。
* @param instance
* @return
*/
private T injectExtension(T instance)
try
if (objectFactory != null)
for (Method method : instance.getClass().getMethods())
if (isSetter(method))
/**
* Check @link DisableInject to see if we need auto injection for this property
*/
if (method.getAnnotation(DisableInject.class) != null)
continue;
// 原生的参数不能进行依赖注入的!
Class<?> pt = method.getParameterTypes()[0];
if (ReflectUtils.isPrimitives(pt))
continue;
try
/**
* 进行依赖注入的时候方法的名称必须和SPI中存在的名称一致! 或者如果是Spring 中,必须是 bean 的名称
*/
String property = getSetterProperty(method);
Object object = objectFactory.getExtension(pt, property);
if (object != null)
method.invoke(instance, object);
catch (Exception e)
logger.error("Failed to inject via method " + method.getName()
+ " of interface " + type.getName() + ": " + e.getMessage(), e);
catch (Exception e)
logger.error(e.getMessage(), e);
return instance;
二、Dubbo 依赖注入
一个SPI扩展对应一个ExtensionLoader,所有的ExtensionLoader都有ExtensionFactory依赖注入处理工厂,一个SPI对应一个Adaptive(可能是默认的、或者自定义的)
1、ExtensionFactory 怎么获取的
ExtensionLoader 是一个载体,每一个实例都有唯一的一个ExtensionFactory 依赖处理工厂,getAdaptiveExtension 证明这个是一个自适应的,可以根据参数变化而获取不同的实现。
private ExtensionLoader(Class<?> type)
this.type = type;
// 工厂扩展实例
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
1.1 ExtensionFactory 工厂
/**
* ExtensionFactory
*/
@SPI
public interface ExtensionFactory
/**
* 获取扩展实例工厂方法,比如SPi 或者Spring 等等
* Get extension.
*
* @param type object type.
* @param name object name.
* @return object instance.
*/
<T> T getExtension(Class<T> type, String name);
1.2 查看配置
META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionFactory
adaptive=org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=org.apache.dubbo.common.extension.factory.SpiExtensionFactory
1.3 自定义扩展,根据顺序获取扩展实例
这里是自定义的一个扩展,根据当前工程中所有的ExtensionFactory实例,谁先获取到一个就使用谁的!
/**
* AdaptiveExtensionFactory 依赖注入工厂
*/
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory
private final List<ExtensionFactory> factories;
public AdaptiveExtensionFactory()
ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
for (String name : loader.getSupportedExtensions())
list.add(loader.getExtension(name));
factories = Collections.unmodifiableList(list);
@Override
public <T> T getExtension(Class<T> type, String name)
// 依赖注入 根据第一匹配原则去查找,如果SPI中有 使用 SpiExtensionFactory,如果Spring 容器中有 使用Spring 容器中的!
for (ExtensionFactory factory : factories)
T extension = factory.getExtension(type, name);
if (extension != null)
return extension;
return null;
1.4 SpiExtensionFactory 获取到SPI的注入
获取这个注入Class的是否为SPI的实现,获取到一个扩展的实例,然后根据参数动态的获取到具体的实例。
/**
* SpiExtensionFactory 处理相关的依赖
*/
public class SpiExtensionFactory implements ExtensionFactory
@Override
public <T> T getExtension(Class<T> type, String name)
if (type.isInterface() && type.isAnnotationPresent(SPI.class))
ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
//依赖注入必须实现 接口方法必须实现 Adaptive
if (!loader.getSupportedExtensions().isEmpty())
return loader.getAdaptiveExtension();
return null;
2、ZookeeperTransporter 怎么获取的?
injectExtension 这个方法,获取到了方法参数org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter 这个class的名称 and 方法的名称
META-INF/dubbo/internal/org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter
curator=org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperTransporter
有了Class,SpiExtensionFactory这个里面获取到SPI的信息一定能够获取得到具体的扩展类的实例,使用了默认的自定义扩展,根据URL进行获取具体的实例。
@SPI("curator")
public interface ZookeeperTransporter
@Adaptive(Constants.CLIENT_KEY, Constants.TRANSPORTER_KEY)
ZookeeperClient connect(URL url);
默认的自定义扩展
2.1 AdaptiveExtensionFactory 依赖注入
2.2 获取SPI的扩展实现类
2.3 返回扩展 ZookeeperTransporter$Adaptive
package org.apache.dubbo.remoting.zookeeper;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class ZookeeperTransporter$Adaptive implements org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter
public org.apache.dubbo.remoting.zookeeper.ZookeeperClient connect(org.apache.dubbo.common.URL arg0)
if (arg0 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg0;
String extName = url.getParameter("client", url.getParameter("transporter", "curator"));
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter) name from url (" + url.toString() + ") use keys([client, transporter])");
org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter extension = (org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter)ExtensionLoader.getExtensionLoader(org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter.class).getExtension(extName);
return extension.connect(arg0);
3. 方法名称有何用
spring 依赖注入可以根据方法名称、然后在根据类型注入具体的实现。
org.apache.dubbo.config.spring.extension.SpringExtensionFactory#getExtension
public <T> T getExtension(Class<T> type, String name)
//SPI should be get from SpiExtensionFactory
if (type.isInterface() && type.isAnnotationPresent(SPI.class))
return null;
for (ApplicationContext context : CONTEXTS)
if (context.containsBean(name))
Object bean = context.getBean(name);
if (type.isInstance(bean))
return (T) bean;
logger.warn("No spring extension (bean) named:" + name + ", try to find an extension (bean) of type " + type.getName());
if (Object.class == type)
return null;
for (ApplicationContext context : CONTEXTS)
try
return context.getBean(type);
catch (NoUniqueBeanDefinitionException multiBeanExe)
logger.warn("Find more than 1 spring extensions (beans) of type " + type.getName() + ", will stop auto injection. Please make sure you have specified the concrete parameter type and there's only one extension of that type.");
catch (NoSuchBeanDefinitionException noBeanExe)
if (logger.isDebugEnabled())
logger.debug("Error when get spring extension(bean) for type:" + type.getName(), noBeanExe);
logger.warn("No spring extension (bean) named:" + name + ", type:" + type.getName() + " found, stop get bean.");
return null;
三、源码流程
无论是Adaptive 或者直接调用,都会触发 getExtension这个方法,获取扩展的具体的实现。
DynamicConfigurationFactory factories = ExtensionLoader
.getExtensionLoader(DynamicConfigurationFactory.class)
.getExtension(url.getProtocol());
ZookeeperTransporter zookeeperTransporter = ExtensionLoader.getExtensionLoader(ZookeeperTransporter.class).getAdaptiveExtension();
ZookeeperTransporter$Adaptive 中根据参数调用的。
org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter extension = (org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter)ExtensionLoader.getExtensionLoader(org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter.class).getExtension(extName);
- org.apache.dubbo.common.extension.ExtensionLoader#getExtension
- org.apache.dubbo.common.extension.ExtensionLoader#createExtension
- org.apache.dubbo.common.extension.ExtensionLoader#injectExtension
- org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory#getExtension
- org.apache.dubbo.common.extension.factory.SpiExtensionFactory#getExtension
以上是关于Dubbo-Dubbo SPI 依赖注入的主要内容,如果未能解决你的问题,请参考以下文章