概述
Dubbo的一大特点就是扩展机制,在框架里很多地方都能看到它的身影。相比JDK SPI(Service Provider Interface)进行了加强,Dubbo SPI的扩展有几大特性:
- 自动包装
- 自动装配
- 自动适配
- 自动激活
ExtensionLoader
Dubbo SPI 主类,实现了扩展机制。Dubbo自己的各种扩展信息都放在各自的配置文件里,都放在各jar的META-INF/dubbo/接口全限定名,内容为:扩展名=扩展实现类的全限定名(多个实现类用换行符分隔)。比如META-INF/dubbo/com.alibaba.dubbo.rpc.Protocol,内容为:
xxx=com.alibaba.xxx.XxxProtocol
xxx2=com.alibaba.xxx.Xxx2Protocol
getExtensionLoader
一类扩展接口由一个ExtensionLoader实例去维护,扩展加载器和扩展接口是一一对应的。
/**
* key:扩展接口
* value:扩展加载器实例对象
*/
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
/**
* 根据扩展接口,获得对应的扩展加载器,扩展加载器和扩展接口是一一对应的
* 扩展接口,必须有@SPI注解
*
* @param type
* @param <T>
* @return
*/
@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!");
}
// 扩展接口,必须有@SPI注解
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;
}
getExtension
根据扩展名获取扩展实例,首先从缓存中取,没有命中就新创建。
/**
* key:扩展名
* value:扩展实现类的对象
*/
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();
/**
* 根据扩展名,返回对应的扩展实现类的对象
* 只在这里会创建扩展对象实例,所以是需要才会创建对象
*
* @param name
* @return
*/
@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;
}
loadFile
从配置文件中读取,扩展名和扩展实现类的映射关系。比如,RegistryFactory的扩展,放置在文件 `META-INF/dubbo/internal/com.alibaba.dubbo.registry.RegistryFactory` 中,loadFile() 方法会读取ClassPath下的所有这个文件,依次读取加载。
自动包装
如果某个扩展实现是一个包装器,拥有一个扩展接口为参数的构造函数,那么ExtensionLoader会将每个扩展实现都用这个包装器进行包装。
比如:
public class XxxProtocolWrapper implemenets Protocol {
Protocol impl;
public XxxProtocol(Protocol protocol) { impl = protocol; }
// 接口方法做一个操作后,再调用extension的方法
public void refer() {
//... 一些操作
impl.refer();
// ... 一些操作
}
}
ExtensionLoader中的实现,伪代码
/**
* 扩展接口的Wrapper类型
*/
private Set<Class<?>> cachedWrapperClasses;
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && wrapperClasses.size() > 0) {
// 如果扩展接口有Wrapper类型的扩展实现,就将扩展对象自动包装到Wrapper对象中
// 此处为扩展自动包装特性
for (Class<?> wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
自动装配
类似于Spring的IOC,依赖注入。如果某个扩展实现中有个属性是其他类型的扩展接口。ExtensionLoader通过setter方法判断,会自动设置这个属性。
/**
* 此处为扩展自动装配特性
* 为扩展实现类对象,设置依赖的属性
*
* @param instance
* @return
*/
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
for (Method method : instance.getClass().getMethods()) {
if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 && Modifier
.isPublic(method.getModifiers())) {
// setter方法
Class<?> pt = method.getParameterTypes()[0];
try {
String property = method.getName().length() > 3 ?
method.getName().substring(3, 4).toLowerCase() + method.getName()
.substring(4) :
"";
// 从ExtensionFactory获得指定的属性
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;
}
ExtensionFactory
自动注入的属性是由ExtensionFactory完成的,在ExtensionLoader构造的时候设置了ExtensionFactory。
private ExtensionLoader(Class<?> type) {
this.type = type;
// 是AdaptiveExtensionFactory扩展
objectFactory = (type == ExtensionFactory.class ?
null :
ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
ExtensionFactory本身也有@SPI注解,也是扩展接口,分别是:
- AdaptiveExtensionFactory:有@Adaptive注解,是ExtensionFactory自适配的扩展实现,会循环调用SpiExtensionFactory和SpringExtensionFactory的方法
- SpiExtensionFactory:注入的是某个扩展接口的自适配实现
- SpringExtensionFactory:注入的是Spring bean
AdaptiveExtensionFactory
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
/**
* ExtensionFactory的所有扩展实现
*/
private final List<ExtensionFactory> factories;
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
/**
* 如果type是注解SPI,就返回这个扩展接口的自适应扩展实现
*
* @param type object type.
* @param name object name.
* @param <T>
* @return
*/
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().size() > 0) {
return loader.getAdaptiveExtension();
}
}
return null;
}
SpringExtensionFactory
/**
* 从Spring容器中获取bean
*
* @param type object type.
* @param name object name.
* @param <T>
* @return
*/
@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;
}
自动适配
如果某个扩展接口拥有@Adaptive注解,那么ExtensionLoader能够获取它的自适应扩展实现。自适配的意思是,在扩展接口的方法执行的时候根据url里的某个参数确定调用哪个扩展实现,也就是说在运行的时候才确定,可以做到根据url参数动态指定。
注:扩展接口必须要有@Adaptive注解,可以放在类上,也可以放在方法上。放在类上表示某个扩展实现是自适应的,放在方法上,Dubbo会自动生成代码来完成自适配功能。
private Class<?> getAdaptiveExtensionClass() {
getExtensionClasses();
// cachedAdaptiveClass是某个有@Adaptive的扩展实现
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
// 自动生成自适应的扩展实现类
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
/**
* 自动生成类的字符串,然后编译成class
*
* @return
*/
private Class<?> createAdaptiveExtensionClass() {
String code = createAdaptiveExtensionClassCode();
ClassLoader classLoader = findClassLoader();
// 获取Compiler的扩展实现,编译代码生成class
com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader
.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
自动激活
有些扩展接口,比如Filter等。经常是要由一些列的扩展实现组合使用的。为了简化使用,Dubbo提供了自动激活的功能,通过一个方法获取符合条件的扩展实现,由注解@Activate表示。
参考:https://dubbo.gitbooks.io/dubbo-dev-book/SPI.html