dubbo自定义SPI
为什么dubbo要自己设计一套SPI?
- JDK标准的SPI会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,而且没用上也加载,会很浪费资源;
- 增加了对扩展点IOC和AOP的支持,一个扩展点可以直接setter注入其它扩展点。
- 这是原始JDK spi的代码
ServiceLoader<Command> serviceLoader=ServiceLoader.load(Command.class);
for(Command command:serviceLoader){
command.execute();
}
dubbo在原来的基础上设计了以下功能:
- 原始JDK spi不支持缓存;dubbo设计了缓存对象:spi的key与value 缓存在
cachedInstances
对象里面,它是一个ConcurrentMap; - 原始JDK spi不支持默认值,dubbo设计默认值:
@SPI("dubbo")
代表默认的spi对象。例如:
Protocol的@SPI("dubbo")
就是DubboProtocol
,通过ExtensionLoader.getExtensionLoader(Protocol.class).getDefaultExtension()
拿默认对象 - jdk要用for循环判断对象,dubbo设计getExtension灵活方便,动态获取spi对象。例如:
ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(spi的key)
来提取对象; - 原始JDK spi不支持 AOP功能,dubbo设计增加了AOP功能,在
cachedWrapperClasses
,在原始spi类,包装了XxxxFilterWrapper XxxxListenerWrapper
; - 原始JDK spi不支持 IOC功能,dubbo设计增加了IOC,通过set注入:
injectExtension(T instance)
。
Dubbo的SPI约定
扩展点的配置都放到\META-INF\dubbo\internal
路径下,且文件名为扩展接口的包名+接口名;文件内容为:扩展名=实现类的包名+类名,例Protocol的SPI配置:
\META-INF\dubbo\internal\com.alibaba.dubbo.rpc.Protocol
injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
registry=com.alibaba.dubbo.registry.integration.RegistryProtocol
dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=com.alibaba.dubbo.rpc.support.MockProtocol
扩展点类型
dubbo为了实现IOC和AOP,设计了多种功能不同的扩展点。我们可以根据扩展点功能的不同把扩展点大致分成4类:
扩展点类型 | 说明 |
---|---|
Adaptive | 含有Adaptive注解的扩展点 |
Wrapper | 含有构造函数的参数为扩展点接口类型的扩展点 1.Filter 2.Listener |
Activate | 含有Activate注解的扩展点 |
其他 | 普通扩展点 |
如Protocol的所有扩展点如下:
injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
registry=com.alibaba.dubbo.registry.integration.RegistryProtocol
dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=com.alibaba.dubbo.rpc.support.MockProtocol
我们可以按照上面的规则将所有的Protocol扩展点分类:
扩展点类型 | 名称 |
---|---|
Adaptive | Protocol$Adaptive(动态编译) |
Wrapper | filter,listener |
其他 | injvm,registry,dubbo,mock |
通过ExtensionLoader.getExtensionLoader(Protpcol.class).getAdaptiveExtension()
创建Protpcol的默认扩展点“dubbo”,而如果我们调用得到的这个实例的方法,它的实际调用流程却是
Protocol$Adaptive->ProtocolFilterWrapper->ProtocolListenerWrapper->DubboProtocol
似乎跟Spring的AOP很像,跟一下源码,来一探究竟。
源码分析
- dubbo spi 的目的:获取一个指定实现类的对象。
- 途径:
ExtensionLoader.getExtension(String name)
- 实现路径:
getExtensionLoader(Class<T> type)
就是为该接口new 一个ExtensionLoader,然后缓存起来。
getAdaptiveExtension()
获取一个扩展类,如果@Adaptive注解在类上就是一个装饰类;如果注解在方法上就是一个动态代理类,例如Protocol$Adaptive对象。
getExtension(String name)
获取一个指定扩展点的对象。
在dubbo的源码中随处可见获取扩展点的例子,我们看下面加载Protocol.class的扩展点dubbo
的例子。
package com.alibaba.dubbo.rpc;
@SPI("dubbo")
public interface Protocol {
int getDefaultPort();
@Adaptive
<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
@Adaptive
<T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
void destroy();
}
- 在
META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol
中可以知道Protocol.class
有很多扩展点,其中就有名为dubbo的扩展点。
injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
registry=com.alibaba.dubbo.registry.integration.RegistryProtocol
dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=com.alibaba.dubbo.rpc.support.MockProtocol
1. 获取扩展点加载器
首先认识一下扩展点加载器,他的静态变量是一些全局的缓存,私有变量会在第一次获取该扩展点实例的时候初始化
public class ExtensionLoader<T> {
private static final Logger logger = LoggerFactory.getLogger(ExtensionLoader.class);
/***所有ExtensionLoader共享变量***/
//扩展点的文件路径
private static final String SERVICES_DIRECTORY = "META-INF/services/";
//扩展点的文件路径
private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
//扩展点的文件路径
private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";
private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
//缓存所有的ExtensionLoader,key是扩展点的接口类型
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
//缓存扩展点的一个实例
private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();
// ==============================
/*****当前ExtensionLoader的私有变量****/
//扩展点的接口类型
private final Class<?> type;
//扩展点IOC的实例来源
private final ExtensionFactory objectFactory;
//普通扩展点的名称
private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>();
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String,Class<?>>>();
private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>();
//adaptive的类
private volatile Class<?> cachedAdaptiveClass = null;
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();
//扩展点的默认名称@SPI中的value
private String cachedDefaultName;
//缓存adaptive实例
private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
//缓存包装类型的扩展点
private Set<Class<?>> cachedWrapperClasses;
getExtensionLoader()首先从缓存中获取该扩展点的ExtensionLoader,如果缓存中不存在创建并缓存起来且key为扩展点的接口类型。
- 执行流程分析
-----------------------ExtensionLoader.getExtensionLoader(Class<T> type)
ExtensionLoader.getExtensionLoader(Container.class)
-->this.type = type;
-->objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
-->ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()
-->this.type = type;
-->objectFactory =null;
/**
* @Author pengyunlong
* @Description 静态方法,单例模式
* 首先从缓存中获取扩展点加载器,如果缓存中不存在则创建
* @param
* @Date 2018/6/11 11:36
*/
@SuppressWarnings("unchecked")
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
if (type == null)
throw new IllegalArgumentException("Extension type == null");
if (!type.isInterface()) {
throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
}
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type(" + type +
") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
}
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
//缓存中部存在则创建
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
/**
* @Author pengyunlong
* @Description 构造方法
* 扩展点加载器
* @param
* @Date 2018/6/7 18:38
*/
private ExtensionLoader(Class<?> type) {
//当前扩展点的接口类型必须,含有SPI注解
this.type = type;
//objectFactory IOC需要从这个变量中加载对象实例并注入
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
执行以上代码完成了2个属性的初始化
- 每个一个ExtensionLoader都包含了2个值: type 和 objectFactory
Class<?> type;
:要加载扩展点的接口
ExtensionFactory objectFactory
:为dubbo的IOC提供所有对象 - new 一个ExtensionLoader 存储在
ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS
关于这个objectFactory的一些细节:
- objectFactory就是通过
ExtensionLoader.getExtensionLoader(ExtensionFactory.class)
来实现的,它的objectFactory=null; - objectFactory实际上是ExtensionFactory.class的Adaptive扩展。
getAdaptiveExtension()
获取一个扩展类,如果@Adaptive注解在类上就是一个装饰类;如果注解在方法上就是一个动态代理类。而在ExtensionFactory.class
的所有扩展实现中AdaptiveExtensionFactory类上有@Adaptive注解,所以ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()
得到的就是AdaptiveExtensionFactory实例。AdaptiveExtensionFactory为dubbo的IOC提供所有对象,内部包含其他两个扩展点SpiExtensionFactory,SpringExtensionFactory,后面会通过它们加载spring和dubbo中的实例注入到目标对象的属性中;
【Dubbo】Adaptive
/**
* AdaptiveExtensionFactory
*/
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
private final List<ExtensionFactory> factories;
/**
* @Author pengyunlong
* @Description 获取到其他ExtensionFactory的实现,并创建ExtensionFactory的实例
* SpiExtensionFactory,SpringExtensionFactory
* @param
* @Date 2018/6/7 17:58
*/
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);
}
/**
* @Author pengyunlong
* @Description 从ExtensionFactory实例中(包括spring容器和spi),加载扩展点指定扩展点实例
* @param
* @Date 2018/6/7 18:01
*/
public <T> T getExtension(Class<T> type, String name) {
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
}
}
/**
* SpiExtensionFactory
*/
public class SpiExtensionFactory implements ExtensionFactory {
public <T> T getExtension(Class<T> type, String name) {
if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
if (!loader.getSupportedExtensions().isEmpty()) {
return loader.getAdaptiveExtension();
}
}
return null;
}
}
package com.alibaba.dubbo.config.spring.extension;
/**
* SpringExtensionFactory
*/
public class SpringExtensionFactory implements ExtensionFactory {
@SuppressWarnings("unchecked")
public <T> T getExtension(Class<T> type, String name) {
for (ApplicationContext context : contexts) {
if (context.containsBean(name)) {
Object bean = context.getBean(name);
if (type.isInstance(bean)) {
return (T) bean;
}
}
}
return null;
}
}
2.加载指定的扩展点
首先从缓存中获取,如果缓存中不存在则通过createExtension(name)
创建并加入缓存
- 代码执行流程
-----------------------getExtension(String name)
getExtension(String name) //指定对象缓存在cachedInstances;get出来的对象wrapper对象,例如protocol就是ProtocolFilterWrapper和ProtocolListenerWrapper其中一个。
-->createExtension(String name)
-->getExtensionClasses()
-->injectExtension(T instance)//dubbo的IOC反转控制,就是从spi和spring里面提取对象赋值。
-->objectFactory.getExtension(pt, property)
-->SpiExtensionFactory.getExtension(type, name)
-->ExtensionLoader.getExtensionLoader(type)
-->loader.getAdaptiveExtension()
-->SpringExtensionFactory.getExtension(type, name)
-->context.getBean(name)
-->injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance))//AOP的简单设计
/**
* Find the extension with the given name. If the specified name is not found, then {@link IllegalStateException}
* will be thrown.
* 根据扩展点名称找到指定的扩展点,首先从缓存中获取,如果缓存中不存在则创建
*/
@SuppressWarnings("unchecked")
public T getExtension(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name == null");
if ("true".equals(name)) {
return getDefaultExtension();
}
Holder<Object> holder = cachedInstances.get(name);
if (holder == null) {
cachedInstances.putIfAbsent(name, new Holder<Object>());
holder = cachedInstances.get(name);
}
Object instance = holder.get();
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
//创建扩展点实例
instance = createExtension(name);
holder.set(instance);
}
}
}
return (T) instance;
}
创建扩展点实例
创建扩展点实例的过程:加载字节码->创建实例-> 注入属性->包装,所以我们最后拿到的扩展点实例其实有可能是一个包装类。dubbo的IOC通过set注入完成,AOP通过wapper包装完成。
/**
* @Description
* 加载字节码
* 创建实例
* 注入属性
* 包装
*/
@SuppressWarnings("unchecked")
private T createExtension(String name) {
//1.获取指定扩展点的Class
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
//2.创建扩展点实例
EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
//3.实现dubbo IOC功能,从spring和dubbo中注入属性到扩展点实例中来
injectExtension(instance);
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
for (Class<?> wrapperClass : wrapperClasses) {
//4.实现dubbo AOP功能,包装扩展点实例
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
type + ") could not be instantiated: " + t.getMessage(), t);
}
}
- 解析该扩展点的类名
从三个路径加载spi配置的class到缓存中,META-INF/dubbo/internal/
、META-INF/dubbo/
、META-INF/services/
。loadfile()
加载过程中还会解析class中包含的注解来填充一些缓存变量。
变量名 | 值 |
---|---|
cachedAdaptiveClass | 含有Adaptive注解的class |
cachedWrapperClasses | 无adative注解,并且构造函数包含目标接口(type)类型的class |
cachedActivates | 剩下的类含有Activate注解的class |
cachedNames | 其余的class |
/**
* @Author pengyunlong
* @Description 如果缓存为空则加载所有的扩展class并缓存起来
* @param
* @Date 2018/6/7 17:08
*/
private Map<String, Class<?>> getExtensionClasses() {
Map<String, Class<?>> classes = cachedClasses.get();
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
classes = loadExtensionClasses();
cachedClasses.set(classes);
}
}
}
return classes;
}
/**
* @Author pengyunlong
* @Description 从三个路径加载spi配置的class到缓存中,cachedDefaultName为spi注解的value
* META-INF/dubbo/internal/ META-INF/dubbo/ META-INF/services/
* @param
* @Date 2018/6/7 17:18
*/
// synchronized in getExtensionClasses
private Map<String, Class<?>> loadExtensionClasses() {
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation != null) {
String value = defaultAnnotation.value();
if (value != null && (value = value.trim()).length() > 0) {
String[] names = NAME_SEPARATOR.split(value);
if (names.length > 1) {
throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
+ ": " + Arrays.toString(names));
}
if (names.length == 1) cachedDefaultName = names[0];
}
}
Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
loadFile(extensionClasses, DUBBO_DIRECTORY);
loadFile(extensionClasses, SERVICES_DIRECTORY);
return extensionClasses;
}
通过把配置文件META-INF/dubbo/internal/com.alibaba.dubbo.rpc. Protocol
(fileName = dir + type.getName();
)的内容,存储在缓存变量里面。
关于loadfile的一些细节
cachedAdaptiveClass
如果这个class含有adative注解就赋值,例如ExtensionFactory,而例如Protocol在这个环节是没有的。cachedWrapperClasses
只有当该class无adative注解,并且构造函数包含目标接口(type)类型,例如protocol里面的spi就只有ProtocolFilterWrapper和ProtocolListenerWrapper
能命中cachedActivates
剩下的类,包含Activate注解cachedNames
剩下的类就存储在这里。
/**
* @Author pengyunlong
* @Description 从指定目录读取Spi配置文件,分析class并加入缓存
* 1.cachedAdaptiveClass 含有Adaptive注解的class
* 2.cachedWrapperClasses 含有指定参数的构造方法的class
* 3.cachedActivates 含有Activate注解的class
* 4.cachedNames 其余的class
* @param
* @Date 2018/6/7 17:13
*/
private void loadFile(Map<String, Class<?>> extensionClasses, String dir){
String fileName = dir + type.getName();
//遍历SPI文件的每一行配置
while ((line = reader.readLine()) != null) {
Class<?> clazz = Class.forName(line, true, classLoader);
//扩展点实例类上有@Adaptive注解直接设置cachedAdaptiveClass
if (clazz.isAnnotationPresent(Adaptive.class)) {
if(cachedAdaptiveClass == null) {
cachedAdaptiveClass = clazz;
} else if (! cachedAdaptiveClass.equals(clazz)) {
throw new
}
try {
clazz.getConstructor(type);
//如果扩展点实例的是含有type类型参数的构造方法则加入cachedWrapperClasses集合中
Set<Class<?>> wrappers = cachedWrapperClasses;
if (wrappers == null) {
cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
wrappers = cachedWrapperClasses;
}
wrappers.add(clazz);
} catch (NoSuchMethodException e) {
Activate activate = clazz.getAnnotation(Activate.class);
if (activate != null) {
cachedActivates.put(names[0], activate);
}
//其余情况则将扩展点类名加入cachedNames,key为class
for (String n : names) {
if (! cachedNames.containsKey(clazz)) {
cachedNames.put(clazz, n);
}
Class<?> c = extensionClasses.get(n);
if (c == null) {
extensionClasses.put(n, clazz);
} else if (c != clazz) {
throw new
}
}
}
}
}
- 创建实例并加入缓存
EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
IOC注入
这一步主要是实现dubbo自己的IOC,遍历扩展实例的方法查找set方法,然后从spring和dubbo容器中查找对应属性值,并反射调用set方法将属性注入到扩展点的实例中。
/**
* @Author pengyunlong
* @Description 含有set开头的方法则动态属性注入
* @param
* @Date 2018/6/7 17:50
*/
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
for (Method method : instance.getClass().getMethods()) {
//寻找set方法
if (method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {
Class<?> pt = method.getParameterTypes()[0];
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;
}
前面说到在ExtensionLoader的构造方法中
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
所以objectFactory 是ExtensionFactory的扩展点(AdaptiveExtensionFactory、SpiExtensionFactory、SpringExtensionFactory
)中的一个,而AdaptiveExtensionFactory
含有@Adaptive
所以通过getAdaptiveExtension
拿到的实际是AdaptiveExtensionFactory
。
Object object = objectFactory.getExtension(pt, property);
这句代码主要就是通过SpiExtensionFactory和SpringExtensionFactory来查找property实例。AdaptiveExtensionFactory.getExtension
会从SpiExtensionFactory、SpringExtensionFactory
中查找指定类型或名称实现类。
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
private final List<ExtensionFactory> factories;
/**
* @Author pengyunlong
* @Description 获取到其他ExtensionFactory的实现,并创建ExtensionFactory的实例
* SpiExtensionFactory,SpringExtensionFactory
* @param
* @Date 2018/6/7 17:58
*/
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);
}
/**
* @Author pengyunlong
* @Description 从ExtensionFactory实例中(包括spring容器和spi),加载扩展点指定扩展点实例
* @param
* @Date 2018/6/7 18:01
*/
public <T> T getExtension(Class<T> type, String name) {
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
}
}
最后通过method.invoke(instance, object);
实现注入,这样扩展点的实例就创建并注入完成了。
IOC说明
- dubbo扩展未知类的属性来源分为:spi 和spring
spi的扩展对象存储在SpiExtensionFactory
spring的扩展对象存储在 SpringExtensionFactory - SpringExtensionFactory的设计初衷:
a. 设计的目的:方便开发者对扩展未知类的配置(可以用spi配置也可以spring bean实现)
b. SpringExtensionFactory在provider发布或consumer引用一个服务的时候,会把spring的容器托付给SpringExtensionFactory中去.具体代码为:ReferenceBean.setApplicationContext 和 ServiceBean.setApplicationContext
c. 当SpiExtensionFactory没有获取到对象的时候会遍历SpringExtensionFactory中的spring容器来获取要注入的对象。
具体代码:AdaptiveExtensionFactory.getExtension
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
SpringExtensionFactory.addApplicationContext(applicationContext);
}
public <T> T getExtension(Class<T> type, String name) {
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
}
- SpringExtensionFactory目前的作用?
SpringExtensionFactory前期的设计初衷非常好,但是后来执行偏离了,没有按这个初衷去落地。因为从这SpringExtensionFactory.getExtension代码(如下:)可以看出,是从ApplicationContext获取对象的。
public <T> T getExtension(Class<T> type, String name) {
for (ApplicationContext context : contexts) {
if (context.containsBean(name)) {
Object bean = context.getBean(name);
if (type.isInstance(bean)) {
return (T) bean;
}
}
}
return null;
}
但是目前这套系统没有配置spring对象的任何痕迹;甚至连配置自定义filter类,也无法实现spring bean配置,只能spi配置。
AOP包装
我们在第1步加载字节码的时候已经填充了wrapperClasses这个缓存变量,而且这个缓存中的所有class均含有以扩展点接口类型为方法参数的构造方法(clazz.getConstructor(type);不会抛出异常
)。遍历所有的wrapper,嵌套循环生成包装类。
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
for (Class<?> wrapperClass : wrapperClasses) {
//4.实现dubbo AOP功能,包装扩展点实例
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
实际上在这里就是ProtocolFilterWrapper
和ProtocolListenerWrapper
对DubboProtocol
的循环包装。
public class ProtocolFilterWrapper implements Protocol {
private final Protocol protocol;
public ProtocolFilterWrapper(Protocol protocol) {
if (protocol == null) {
throw new IllegalArgumentException("protocol == null");
}
this.protocol = protocol;
}
...
}
public class ProtocolListenerWrapper implements Protocol {
private final Protocol protocol;
public ProtocolListenerWrapper(Protocol protocol) {
if (protocol == null) {
throw new IllegalArgumentException("protocol == null");
}
this.protocol = protocol;
}
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
return protocol.export(invoker);
}
return new ListenerExporterWrapper<T>(protocol.export(invoker),
Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
.getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
}
....
}
总结
至此获取扩展点实例的过程就全部完成了
image.png
参考资料
SPI
https://blog.csdn.net/sigangjun/article/details/79071850
网友评论