META-INF/dubbo下的文件可以使用#注释
ExtensionLoader
- 基本字段说明
以下字段可以分为class字段(如cacheNames)与实例字段(如cacheInstances)
public class ExtensionLoader {
//对不同的接口记录对应的ExtensionLoader
private static final ConcurrentMap, ExtensionLoader>> EXTENSION_LOADERS = new ConcurrentHashMap<>();
//对不同的class记录产生的实例,共享所有接口对应的实现实例
private static final ConcurrentMap, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>();
//loader对应的接口
private final Class> type;
//对接口ExtensionFactory是null,其余接口是AdaptiveExtensionFactory实例
private final ExtensionFactory objectFactory;
//记录当前接口对应的实现class及className
private final ConcurrentMap, String> cachedNames = new ConcurrentHashMap<>();
//Holder内部是volatile,记录className及对应的class
private final Holder
核心逻辑研究
- 使用原则
//获取META-INF配置文件中包含哪些实现
extensionLoader.getExtensionClass()
//当上下文逻辑中指定实现名称时使用
extensionLoader.getExtension(name);
//当上下文逻辑中没有指定名称时使用
extensionLoader.getAdaptiveExtension()
- 测试入口
//测试代码
public void testDubboSpi() {
//初始化ExtensionLoader实例(class字段及实例字段)
//初始化ExtensionLoader实例,仅设置type和objectFactory字段,不会初始化class相关字段
ExtensionLoader extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class);
// 内部调用extensionLoader.getExtensionClass初始化class相关字段,获取包裹了wrapper的实例
Robot bumblebee = extensionLoader.getExtension("bumblebee");
bumblebee.sayHello();
// 测试自动注入Battery字段
Robot optimusPrime = extensionLoader.getExtension("optimusPrime");
optimusPrime.sayHello();
// 获取自动注入
Robot compoundRobot = extensionLoader.getExtension("compound");
compoundRobot.sayHello();
}
- ExtensionLoader.getExtensionLoader(Robot.class)
//函数调用链
ExtensionLoader.getExtensionLoader(Robot.class)
ExtensionLoader.getExtensionLoader(ExtensionFactory.class))
//未指定实现,获取adaptive实现
ExtensionLoader.getAdaptiveExtension()
//获取AdaptiveExtensionClass并初始化adaptive实例
getAdaptiveExtensionClass().newInstance()
//获取META-INF中对应的名称与实现的对应关系
getExtensionClasses()
//扫描META-INF/dubbo等默认配置路径
loadExtensionClasses()
//根据配置文件中名称与实现初始化loader中class字段
loadClass()
//newInstance()时调用默认构造函数,初始化loader中实例字段并设置SpiFactory和SpringFactory
AdaptiveExtensionFactory()
//将AdaptiveExtensionFactory设置到ExtensionLoader中
private ExtensionLoader(Class> type) {
this.type = type;
//第一次调用ExtensionLoader.getExtensionLoader(type)时初始化ExtensionLoader实例
//初始化实例时仅设置type和objectFactory字段
//type!=ExtensionFactory时objectFactory为AdaptiveExtensionFactory实例
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
private T createAdaptiveExtension() {
//newInstance()时会调用默认构造函数,如AdaptiveExtensionFactory()
//这里调用injectExtension方法的目的是为手工编码的自适应拓展注入依赖
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
}
private Class> getAdaptiveExtensionClass() {
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
private Map> loadExtensionClasses() {
//根据@SPI("")设置defaultName
cacheDefaultExtensionName();
Map> extensionClasses = new HashMap<>();
//在以下目录寻找SPI配置并初始化本ExtensionLoader中的相关字段
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
return extensionClasses;
}
//处理spi配置中每一行记录
//设置AdaptiveClass,WrapperClass,class->className,className->class字段
private void loadClass(Map> extensionClasses, java.net.URL resourceURL, Class> clazz, String name) throws NoSuchMethodException {
if (clazz.isAnnotationPresent(Adaptive.class)) {
//设置cachedAdaptiveClass字段,多于一个AdaptiveClass抛出异常
cacheAdaptiveClass(clazz);
//通过clazz.getConstructor(type)是否报异常来判断
} else if (isWrapperClass(clazz)) {
//设置cachedWrapperClasses字段
cacheWrapperClass(clazz);
} else {
// 检测 clazz 是否有默认的构造方法,如果没有,则抛出异常
clazz.getConstructor();
String[] names = NAME_SEPARATOR.split(name);
//判断并设置cachedActivates字段
cacheActivateClass(clazz, names[0]);
for (String n : names) {
//设置cachedNames
cacheName(clazz, n);
//返回后设置cachedClasses
saveInExtensionClass(extensionClasses, clazz, name);
}
}
}
public AdaptiveExtensionFactory() {
ExtensionLoader loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
List list = new ArrayList();
//初始化SpiExtensionFactory和SpringExtensionFactory实例,设置cachedInstances字段和EXTENSION_INSTANCES字段
for (String name : loader.getSupportedExtensions()) {
list.add(loader.getExtension(name));
}
factories = Collections.unmodifiableList(list);
}
- extensionLoader
.getExtension("bumblebee")
//META-INF中配置
bumblebee = com.my.study.business.impl.dubbo.pojo.BumblebeeRobot
wrapper = com.my.study.business.impl.dubbo.pojo.RobotWrapper
//初始化实例
//Ioc注入,Wrapper处理
private T createExtension(String name) {
//初始化当前loader涉及的实现class(不初始化实例)
Class> clazz = getExtensionClasses().get(name);
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
// 初始化新实例,调用默认构造函数
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
// Ioc注入其他实现字段
injectExtension(instance);
Set> wrapperClasses = cachedWrapperClasses;
if (CollectionUtils.isNotEmpty(wrapperClasses)) {
for (Class> wrapperClass : wrapperClasses) {
//支持多个wrapper,多重代理,实现的不错
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
}
- extensionLoader.getExtension("optimusPrime")
//函数调用链
//extensionLoader.getExtension时扫描
getExtension(robot).injectExtension(instance)
adaptiveExtensionFactory.getExtension()
//若type声明了@Spi,则走spiExtensionFactory,否则走springExtensionFactory,如何初始化SpringExtensionFactory呢?
spiExtensionFactory.getExtension()
//未指定battery实现,获取AdaptiveExtension
extensionLoader.getAdaptiveExtension()
//获取AdaptiveExtensionClass:首先判断META-INF配置文件中是否指定AdaptiveExtensionClass,如果未指定则临时创建代理类
extensionLoader.getAdaptiveExtensionClass()
//创建代理类
Class c=createAdaptiveExtensionClass()
//创建代理类实例并在上文injectExtension(instance)中通过setter方法注入
private T injectExtension(T instance) {
if (objectFactory != null) {
for (Method method : instance.getClass().getMethods()) {
//找到setter方法
if (isSetter(method)) {
String property = getSetterProperty(method);
//adaptiveExtensionFactory调用,property其实无用
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
//set回去
method.invoke(instance, object);
private Class> getAdaptiveExtensionClass() {
getExtensionClasses();
if (cachedAdaptiveClass != null) {
//如果META-INF中配置了AdaptiveExtensionClass则直接使用(如AdaptiveExtensionFactory.class)
return cachedAdaptiveClass;
}
//如未配置,则需要临时创建
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
private Class> createAdaptiveExtensionClass() {
//创建代理类java code,code中每个函数根据入参Url及type函数@Adaptive注解指定的名称选择并调用实现中对应的函数。
//接口中某method未声明@Adaptive时,代理类中该method body为throw UnsupportOperationException()
//为什么该代理类要临时创建?因为需要继承对应的接口并实现相应的方法,无法使用通用的逻辑,创建并完成Ioc注入后后续调用可以直接使用。
String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
ClassLoader classLoader = findClassLoader();
//选择创建代理类的库,使用META-INF文件中指定的AdaptiveCompiler
org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
//AdaptiveCompiler
public Class> compile(String code, ClassLoader classLoader) {
Compiler compiler;
ExtensionLoader loader = ExtensionLoader.getExtensionLoader(Compiler.class);
String name = DEFAULT_COMPILER;
// 使用设置的compile
if (name != null && name.length() > 0) {
compiler = loader.getExtension(name);
} else {
//使用默认的compiler,默认是JavassistByte
compiler = loader.getDefaultExtension();
}
return compiler.compile(code, classLoader);
}
//JavassitByte生成的代码
package com.my.study.business.impl.dubbo.pojo.battery;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class Battery$Adaptive implements com.my.study.business.impl.dubbo.pojo.battery.Battery {
public void uninstall(org.apache.dubbo.common.URL arg0) {
//未声明@Activate的method直接写入异常抛出
throw new UnsupportedOperationException("The method public abstract void com.my.study.business.impl.dubbo.pojo.battery.Battery.uninstall(org.apache.dubbo.common.URL) of interface com.my.study.business.impl.dubbo.pojo.battery.Battery is not adaptive method!");
}
public void install(org.apache.dubbo.common.URL arg0) {
if (arg0 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg0;
//从url中获取实现的名称
String extName = url.getParameter("id", url.getParameter("type"));
if(extName == null) throw new IllegalStateException("Failed to get extension (com.my.study.business.impl.dubbo.pojo.battery.Battery) name from url (" + url.toString() + ") use keys([id, type])");
com.my.study.business.impl.dubbo.pojo.battery.Battery extension = (com.my.study.business.impl.dubbo.pojo.battery.Battery)ExtensionLoader.getExtensionLoader(com.my.study.business.impl.dubbo.pojo.battery.Battery.class).getExtension(extName);
extension.install(arg0);
}
}
- batteryExtensionLoader.getActivateExtension(URL.valueOf("?type=water"), new String[] {"nuclear"}, null)
与Ioc无关,直接调用getActivateExtension()才会获取满足@Activate条件的Extension
public List getActivateExtension(URL url, String[] values, String group) {
//获取META-INF配置中未被new String[] {"nuclear"}指定且入参group、url与@Activate.group和value值不违背的extension
if (isMatchGroup(group, activateGroup)) {
T ext = getExtension(name);
if (!names.contains(name)
&& !names.contains(REMOVE_VALUE_PREFIX + name)
&& isActive(activateValue, url)) {
exts.add(ext);
}
}
//获取META-INF配置中由new String[] {"nuclear"}指定的extension
for (int i = 0; i < names.size(); i++) {
String name = names.get(i);
if (!name.startsWith(REMOVE_VALUE_PREFIX)
&& !names.contains(REMOVE_VALUE_PREFIX + name)) {
T ext = getExtension(name);
usrs.add(ext);
}
}
//组合以上结果
exts.addAll(usrs);
DubboSpiIoc vs SpringIoc
DubboSpi与SpringIoc二者都是从配置依赖注入策略。
- SpringIoc
Spring可以通过@Component注入策略,可以使用@Qualifier引用注入,可以选择lazyInit延迟初始化,可以使用applicationContext.getBean(name,class)根据函数参数使用对应的实现
- DubboSpiIoc
在meta中配置策略,通过ExtensionLoader手动获取指定的策略,支持Ioc扫描注入临时产生的代理类以实现参数动态策略选择。
DubboSpi包含的功能SpringIoc都有,为啥还要使用DubboSpi?是为了保持轻量和解耦Spring吗?