1. 功能概述
- ExtensionLoader包含了扩展机制的逻辑,类似ClassLoader的功能用途。ExtensionLoader主要功能是加载约定路径下的SPI文件,获取扩展类的类名,并做Class类、实例的缓存。里面还包含自动包装、自动加载、自适应、自动激活等功能的实现逻辑。
2. 功能分析
2.1 ExtensionLoader类分析
2.1.1)主要成员变量分析
/**
* 扩展接口与ExtensionLoader扩展加载器的映射(类共享变量)
* 1)包含了ExtensionFactory接口与其它接口的映射
* 2)每一个SPI接口对应一个ExtensionLoader
* 3)static 静态成员变量,对象之间共享(具体的对象时,EXTENSION_LOADERS、EXTENSION_INSTANCES等static变量是没有存值的)
*
*/
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>(64);
/**
* 扩展接口与扩展实例的映射(类共享变量)
*/
private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>(64);
private final Class<?> type; //扩展接口的类型
private final ExtensionFactory objectFactory; //扩展实例的创建工厂(ExtensionFactory也是SPI接口,1)此处的实例为AdaptiveExtensionFactory@xxx,会用存储的多个扩展工厂查找扩展实例,2)当type=ExtensionFactory.class时,objectFactory=null)
private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<>(); //扩展实例类Class与扩展名的映射(该缓存中:多个扩展类可以对应同一个扩展名)
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>(); //当前扩展接口中的扩展名与扩展类Class的映射(该缓存中,一个扩展名对应一个扩展类,根据加载策略中的overridden值判断是做覆盖还是抛出异常)
private final Map<String, Object> cachedActivates = new ConcurrentHashMap<>(); //扩展名与@Active注解对象的映射
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>(); //扩展名与扩展实例的映射
private final Holder<Object> cachedAdaptiveInstance = new Holder<>(); //自适应扩展类的实例
private volatile Class<?> cachedAdaptiveClass = null; //自适应扩展类(一个扩展接口最多只有一个自适应扩展类)
private String cachedDefaultName; //缓存默认的扩展名,即为SPI上声明的扩展名
private volatile Throwable createAdaptiveInstanceError; //创建自适应扩展实例时发生的错误
private Set<Class<?>> cachedWrapperClasses; //扩展接口对应的封装类集合(封装类不是扩展类,所以没有在cachedClasses缓存中)
private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<>(); //加载时扩展类时的异常信息
private static volatile LoadingStrategy[] strategies = loadLoadingStrategies(); //加载的策略
2.1.2)主要成员方法分析
1)构造方法
private ExtensionLoader(Class<?> type) { //私有的构造方法,创建ExtensionLoader实例(指定扩展接口的类型和扩展工厂)
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
- 代码解析:此处获取ExtensionFactory扩展工厂时,采用了递归方法处理,处理逻辑如下
- 若SPI接口是ExtensionFactory,则objectFactory设置为null,因为自身已经是ExtensionFactory类型了
- 若SPI接口非ExtensionFactory,则需要objectFactory实例的值,因为ExtensionFactory本身是SPI接口,所以还需要SPI的方式,先获取到ExtensionLoader,再获取自适应的扩展实例
2)获取扩展加载器
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) { //获取扩展接口对应的扩展加载器ExtensionLoader(从缓存中获取,若不存在则重新创建)
if (type == null) { //扩展类型:不为空且是SPI接口
throw new IllegalArgumentException("Extension type == null");
}
if (!type.isInterface()) {
throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
}
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type (" + type +
") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
}
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) { //每个SPI接口,对应一个扩展加载器ExtensionLoader,若存在直接返回,否则创建ExtensionLoader
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type); //直接从Map中获取值,少了中间变量,更简洁些
}
return loader;
}
3)获取扩展实例
public T getExtension(String name, boolean wrap) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Extension name == null");
}
if ("true".equals(name)) { //扩展名为"true",返回默认扩展实例
return getDefaultExtension();
}
final Holder<Object> holder = getOrCreateHolder(name); //获取扩展名对应实例持有类
Object instance = holder.get();
if (instance == null) { //使用双重判断+synchronized来确保单实例
synchronized (holder) {
instance = holder.get();
if (instance == null) { //若缓存中没有扩展实例,则创建对应实例对象
instance = createExtension(name, wrap);
holder.set(instance);
}
}
}
return (T) instance;
}
4)创建扩展实例
private T createExtension(String name, boolean wrap) { //创建普通的扩展实例
// 先加载扩展接口对应的所有扩展类Class,然后在找出扩展名对应扩展类Class
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) { //配置文件中,若没有查找到扩展名对应的Class类,则抛出扩展发现异常
throw findException(name);
}
try {
//通过Class的newInstance()创建实例(反射机制)
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);
if (wrap) { //使用封装类对扩展实例进行封装(类似AOP功能)
List<Class<?>> wrapperClassesList = new ArrayList<>();
if (cachedWrapperClasses != null) { //当前扩展接口对应的封装类列表,如WrappedExt的封装类列表为Ext5Wrapper1、Ext5Wrapper2
wrapperClassesList.addAll(cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR); //将封装类列表进行排序
Collections.reverse(wrapperClassesList); //将已经排好序的封装类列表进行翻转
}
if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
for (Class<?> wrapperClass : wrapperClassesList) {
Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
/**
* 判断是否使用封装类封装扩展实例
* a)封装类没有带 @Wrapper注解
* b)封装类带有 @Wrapper注解,且扩展名包含在匹配列表matches中,不在不匹配列表mismatches中
*/
if (wrapper == null
|| (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); //用封装类封装扩展类的实例
}
}
}
}
initExtension(instance); //若实例为Lifecycle类型,则调用Lifecycle#initialize进行初始化
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
type + ") couldn't be instantiated: " + t.getMessage(), t);
}
}
5)注入依赖的扩展实例
private T injectExtension(T instance) { //注入依赖的扩展实例
if (objectFactory == null) { //扩展工厂为空时,提前结束
return instance;
}
try {
for (Method method : instance.getClass().getMethods()) {
if (!isSetter(method)) { //只处理set方法
continue;
}
if (method.getAnnotation(DisableInject.class) != null) { //若方法上声明@DisableInject,则不进行注入处理
continue;
}
Class<?> pt = method.getParameterTypes()[0]; //取出set方法中的参数Class
if (ReflectUtils.isPrimitives(pt)) {
continue;
}
try {
String property = getSetterProperty(method); //获取属性名(通过解析方法名称)
Object object = objectFactory.getExtension(pt, property);//此处的objectFactory类型为自适应扩展工厂AdaptiveExtensionFactory,通过遍历其中维护的扩展工厂来获取扩展对象
if (object != null) { //获取到的扩展实例不为空时,则为对象属性设置值,如Ext6扩展接口的实现类Ext6Impl1
method.invoke(instance, object); //使用反射机制调用Set方法,进入扩展对象的依赖注入
}
} 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; //返回处理后的扩展实例
}
6)加载SPI配置文件
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader,
java.net.URL resourceURL, boolean overridden, String... excludedPackages) {
try { //资源放在try里面创建,不使用时会自动被释放
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {//读取每一行,对每一行进行解析
final int ci = line.indexOf('#');
if (ci >= 0) { //若是注释的话,把注释内容去掉,#代表注释
line = line.substring(0, ci); //取#号前面的子串
}
line = line.trim(); //去除字符串头部、尾部的空格
if (line.length() > 0) {//@csy-010 解析的时候,怎么去掉扫描行里面的空格?如SimpleExt对应的配置文件,解:调用trim()方法
try {
String name = null;
int i = line.indexOf('='); //按等号进行分隔
if (i > 0) { //配置的格式为 extName = className,也可以为 className(不带扩展名)
name = line.substring(0, i).trim(); //扩展名(去前后空格)
line = line.substring(i + 1).trim(); //扩展类对应的全路径类名(去前后空格)
}
if (line.length() > 0 && !isExcluded(line, excludedPackages)) { //扩展类的全路径名称,如org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter
loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name, overridden); //根据扩展类名产生Class,并加载到缓存中
}
} catch (Throwable t) { //加载扩展类出现异常时,将异常信息按扩展类的全路径名存起来(某一扩展类加载异常,会把异常信息缓存起来,不影响其它扩展类的加载)
IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
exceptions.put(line, e);
}
}
}
}
} catch (Throwable t) {
logger.error("Exception occurred when loading extension class (interface: " +
type + ", class file: " + resourceURL + ") in " + resourceURL, t);
}
}
- 代码解析:加载SPI文件后,会读取扩展配置文件的所有内容,把所有的扩展名与扩展类解析,并依次放入对应的缓存
7)加载扩展类到缓存中
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name,
boolean overridden) throws NoSuchMethodException {
if (!type.isAssignableFrom(clazz)) { //判断实例类是不是接口type的子类型
throw new IllegalStateException("Error occurred when loading extension class (interface: " +
type + ", class line: " + clazz.getName() + "), class "
+ clazz.getName() + " is not subtype of interface.");
}
if (clazz.isAnnotationPresent(Adaptive.class)) { //缓存自适应扩展类(类上带有@Adaptive注解的扩展类)
cacheAdaptiveClass(clazz, overridden);
} else if (isWrapperClass(clazz)) { //缓存封装类型扩展类(即存在包含以扩展接口为参数的构造方法)
cacheWrapperClass(clazz);
} else { //缓存自动激活扩展类或普通扩展类
clazz.getConstructor();
if (StringUtils.isEmpty(name)) { //什么场景下扩展名为空?解:SPI配置文件中,扩展名为空的情况
name = findAnnotationName(clazz);
if (name.length() == 0) {
throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
}
}
String[] names = NAME_SEPARATOR.split(name); //多个扩展名可以对应一个扩展类,如xxx.Ext10MultiNames配置的内容,如impl,implMultiName=xxx.Ext10MultiNamesImpl
if (ArrayUtils.isNotEmpty(names)) {
cacheActivateClass(clazz, names[0]); //缓存扩展名与@Activate对象的映射。有多个扩展名时,取第一个扩展名作为自动激活缓存的key
for (String n : names) {
cacheName(clazz, n); //缓存扩展类Class与扩展名的映射(允许多个扩展类Class对应同一个扩展名)
saveInExtensionClass(extensionClasses, clazz, n, overridden); //缓存扩展名与扩展类Class的映射
}
}
}
}
- 代码解析:会加载配置文件中的内容,并设置到不同类型的缓存中,比如cachedAdaptiveClass、cachedWrapperClasses、extensionClasses、cachedActivates等
8)获取自动激活的扩展类列表
public List<T> getActivateExtension(URL url, String[] values, String group) { //获取自动激活的扩展列表(将URL中配置的参数与@Activate配置的内容进行比较)
List<T> activateExtensions = new ArrayList<>();
List<String> names = values == null ? new ArrayList<>(0) : asList(values); // 扩展名列表(values是从url中获取的指定key对应的参数值,并按分隔符分隔的值列表)
/**
* 类型一:系统激活的扩展类
*/
if (!names.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) { // 系统激活的扩展类处理,即扩展名列表不包含"-default"
getExtensionClasses(); //加载扩展类。此处没有用到方法的返回值,主要使用方法中的loadExtensionClasses(),值存入成员变量中了,若缓存中没有对应的值,则对应加载并设置到缓存中
for (Map.Entry<String, Object> entry : cachedActivates.entrySet()) { // 遍历从SPI配置文件中加载的@Activate标识的扩展类列表(需要扩展接口有包含@Active注解的实现类)
String name = entry.getKey(); //扩展名
Object activate = entry.getValue(); // @Active对象
String[] activateGroup, activateValue;
if (activate instanceof Activate) { //取注解@Activate上设置的group、value值
activateGroup = ((Activate) activate).group();
activateValue = ((Activate) activate).value();
} else if (activate instanceof com.alibaba.dubbo.common.extension.Activate) { //兼容老版本的功能
activateGroup = ((com.alibaba.dubbo.common.extension.Activate) activate).group();
activateValue = ((com.alibaba.dubbo.common.extension.Activate) activate).value();
} else {
continue;
}
/**
* 自动激活条件匹配逻辑(先比较group、再比较value)
* 1)判断传入的group是否在注解中group的列表值中
* 2)扩展名name不在自定义的列表中(当前处理的扩展类是系统激活的扩展类)
* 3)将注解中声明的value值与url中参数值进行比较
* 若都满足条件,则获取扩展名对应的实例,并加载到自动激活扩展的列表中
*/
if (isMatchGroup(group, activateGroup)
&& !names.contains(name) //为啥要有这个判断?解答:当前处理的是系统激活的扩展类,而names是自定义的扩展名列表,两者分开处理,所以要进行排除
&& !names.contains(REMOVE_VALUE_PREFIX + name) //对应场景:在设置扩展条件时,把系统激活的类去除,如"-order",即不加到扩展类列表中
&& isActive(activateValue, url)) {
activateExtensions.add(getExtension(name)); // 若匹配,则获取扩展名name对应的实例并加载到列表中
}
}
activateExtensions.sort(ActivateComparator.COMPARATOR); //将可激活扩展类列表进行排序
}
List<T> loadedExtensions = new ArrayList<>();
/**
* 类型二:自定义激活的扩展类
*/
for (int i = 0; i < names.size(); i++) {
String name = names.get(i);
// 带有排除符号"-"的Filter不加载
if (!name.startsWith(REMOVE_VALUE_PREFIX)
&& !names.contains(REMOVE_VALUE_PREFIX + name)) { //@csy-007 此处逻辑会在什么场景下进入?解:处理不再cachedActivates缓存中的扩展,如ExtensionLoaderTest.testLoadDefaultActivateExtension
if (DEFAULT_KEY.equals(name)) { //若指定了"default",则调整对应的顺序
if (!loadedExtensions.isEmpty()) {
activateExtensions.addAll(0, loadedExtensions); //@csy-0014 在指定位置加载列表,原来的值会被覆盖吗?不会覆盖,元素会向后移动
loadedExtensions.clear();
}
} else {
loadedExtensions.add(getExtension(name)); //从cachedClasses缓存中获取指定扩展名对应的扩展类,此处若没有查到指定的扩展,是会抛出没找到扩展的异常
}
}
}
if (!loadedExtensions.isEmpty()) {
activateExtensions.addAll(loadedExtensions);
}
return activateExtensions;
}
- 代码解析:自动激活的扩展分为两类
- a)系统激活的扩展类:带有@Activate注解,匹配注解中的group、value获取实例
- b)自定义激活的扩展类:由用户指定的扩展类,可以不带@Activate注解,不用比较group、value值
9)添加扩展到缓存中
public void addExtension(String name, Class<?> clazz) { //添加扩展接口(通过API方式添加,非配置文件中配置)
getExtensionClasses(); // load classes(加载扩展类)
if (!type.isAssignableFrom(clazz)) {
throw new IllegalStateException("Input type " +
clazz + " doesn't implement the Extension " + type);
}
if (clazz.isInterface()) {
throw new IllegalStateException("Input type " +
clazz + " can't be interface!");
}
if (!clazz.isAnnotationPresent(Adaptive.class)) { //非自适应扩展类时
if (StringUtils.isBlank(name)) {
throw new IllegalStateException("Extension name is blank (Extension " + type + ")!");
}
if (cachedClasses.get().containsKey(name)) {
throw new IllegalStateException("Extension name " +
name + " already exists (Extension " + type + ")!");
}
cachedNames.put(clazz, name); //符合条件后,设置到缓存中
cachedClasses.get().put(name, clazz);
} else { //自适应扩展类,即类上带有@Adaptive注解(一个扩展接口,最多只有一个自适应扩展类)
if (cachedAdaptiveClass != null) { //添加扩展时,自适应类已存在,则抛出异常
throw new IllegalStateException("Adaptive Extension already exists (Extension " + type + ")!");
}
cachedAdaptiveClass = clazz; //自适应扩展,是不需要处理扩展名的
}
}
2.2 AdaptiveClassCodeGenerator类分析
2.2.1)主要成员变量分析
private static final Logger logger = LoggerFactory.getLogger(AdaptiveClassCodeGenerator.class);
private static final String CLASSNAME_INVOCATION = "org.apache.dubbo.rpc.Invocation";
private static final String CODE_PACKAGE = "package %s;\n"; //包信息对应的字符串,使用字符串的占位符,来替换具体的值
private static final String CODE_IMPORTS = "import %s;\n"; //导入信息对应的字符串
private static final String CODE_CLASS_DECLARATION = "public class %s$Adaptive implements %s {\n"; //类的声明信息对应的字符串
private static final String CODE_METHOD_DECLARATION = "public %s %s(%s) %s {\n%s}\n"; //方法的声明信息对应的字符串
private static final String CODE_METHOD_ARGUMENT = "%s arg%d"; //方法参数对应的字符串
private static final String CODE_EXTENSION_METHOD_INVOKE_ARGUMENT = "arg%d"; //拼接的内容,用占位符进行处理
private final Class<?> type; //SPI扩展接口
2.2.2)主要成员方法分析
1)自适应类产生
public String generate() {
// no need to generate adaptive class since there's no adaptive method found.
if (!hasAdaptiveMethod()) { //判断是否有自适应方法,如无则抛出异常
throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!");
}
// 构建自适应实现类:包含package语句、import语句、Class声明、SPI接口中各个方法的对应实现
StringBuilder code = new StringBuilder();
code.append(generatePackageInfo()); //把功能点用对应的方法表示,清晰明了,并且使单个方法的内容变少
code.append(generateImports());
code.append(generateClassDeclaration());
Method[] methods = type.getMethods();
for (Method method : methods) { //遍历SPI接口的方法,并对应产生方法对应的代码
code.append(generateMethod(method));
}
code.append("}");
if (logger.isDebugEnabled()) {
logger.debug(code.toString());
}
return code.toString();
}
2)产生方法信息
private String generateMethod(Method method) {
//构建方法:包含方法返回类型、方法名、方法参数、抛出的异常、内容
String methodReturnType = method.getReturnType().getCanonicalName(); //获取规范的返回类型,如java.lang.String
String methodName = method.getName();
String methodContent = generateMethodContent(method); // 产生方法内容
String methodArgs = generateMethodArguments(method); //如:org.apache.dubbo.common.URL arg0, java.lang.String arg1
String methodThrows = generateMethodThrows(method);
// CODE_METHOD_DECLARATION = "public %s %s(%s) %s {\n%s}\n";
return String.format(CODE_METHOD_DECLARATION, methodReturnType, methodName, methodArgs, methodThrows, methodContent);
}
3)产生方法体内容
private String generateMethodContent(Method method) {
Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);
StringBuilder code = new StringBuilder(512);
if (adaptiveAnnotation == null) {
return generateUnsupported(method); //方法未带@Adaptive注解时,产生不支持操作的描述
} else {
int urlTypeIndex = getUrlTypeIndex(method);
// found parameter in URL type
if (urlTypeIndex != -1) {
// Null Point check
code.append(generateUrlNullCheck(urlTypeIndex)); //产生URL非空检查的语句
} else {
// did not find parameter in URL type
//@csy-011 未找到url参数时的处理逻辑是怎样的?遍历参数Class列表,然后依次查看参数Class对应的方法,判断是否有返回值为URL的get方法,若有则进行相关处理
code.append(generateUrlAssignmentIndirectly(method)); //间接地通过方法中的参数获取URL,并产生URL非空检查的语句
}
String[] value = getMethodAdaptiveValue(adaptiveAnnotation); //获取方法上@Adaptive声明的值
boolean hasInvocation = hasInvocationArgument(method); //判断方法参数列表中是否存在Invocation类型参数
code.append(generateInvocationArgumentNullCheck(method)); //产生Invocation类型参数的非空检查的语句
code.append(generateExtNameAssignment(value, hasInvocation)); //产生获取扩展名的语句(**重点逻辑**)
// check extName == null?
code.append(generateExtNameNullCheck(value)); //产生扩展名非空检查的语句
code.append(generateExtensionAssignment()); //产生获取扩展实例的语句
// return statement
code.append(generateReturnAndInvocation(method)); //产生方法调用以及有返回值时返回Return语句
}
return code.toString();
}
3. 问题点答疑
- ExtensionLoader是只有一个实例,还是会有多个?为什么在ExtensionLoader类描述中,说成是单例的?
- 解答:实际测试以及代码分析证明,一个扩展接口就会创建一个ExtensionLoader。ExtensionLoader中有许多static成员变量,那这些就是对象共享的,如ConcurrentMap<Class, ExtensionLoader> EXTENSION_LOADERS、 ConcurrentMap<Class, ExtensionLoader> EXTENSION_LOADERS等等。描述中的信息有些断章取义了,经过完整翻译,原意为:被设计为单例或静态(本身完全静态或使用一些静态字段)
- Pattern.compile(“\s_[,]+\s_”) 这个正则表达式,代表什么含义?
- 解答:\s* 表示0个或多个空格,[,]+ 表示一个或多个逗号
- ExtensionFactory扩展实例的创建工厂是怎么使用的?默认都是SpiExtensionFactonry,怎样指定扩展工厂?
- 解答:a)设值:ExtensionFactory是在ExtensionLoader创建时设置的,通过ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()),默认为扩展名spi对应的扩展工厂,即SpiExtensionFactory。 b)使用:在ExtensionLoader#injectExtension注入依赖时,通过扩展工厂获取扩展实例对象
- ExtensionLoader#EXTENSION_INSTANCES扩展实例的缓存是在什么时候设置的?
- 解答:在创建实例的时候ExtensionLoader#createExtension会判断扩展实例对象是否存在,若不存在则会创建,并且设置到缓存中。
- ExtensionLoader#cachedAdaptiveInstance(自适应类的实例对象),什么情况下会有值?
- 解答:在ExtensionLoader#getAdaptiveExtension获取自适应扩展实例时,在实例为空时,会创建自适应实例,并缓存下来
- AdaptiveExtensionFactory自适应扩展工厂是怎么被使用上的?为什么叫做自适应?AdaptiveExtensionFactory类上@Adaptive的注解是怎么生效的?
- 解答:AdaptiveExtensionFactory类上带有@Adaptvie注解,即为ExtensionFactory扩展接口的自适应扩展类。在ExtensionLoader#loadClass时会按@Adaptive进行分类缓存。而AdaptiveExtensionFactory构造方法中,会把SPI配置文件中支持的扩展工厂放到集合中,在进行依赖注入时使用扩展工厂产生扩展实例时,会依次从扩展工厂中创建实例,只要其它一个扩展工厂能创建出实例即可,所以叫做“自适应”
- 为什么同一个ExtensionLoader同一个扩展名extName,产生的扩展实例是同一个?
- 解答:因为ExtensionLoader相同,那么其缓存的cachedClasses扩展类、cachedInstances扩展实例就是相同的,若缓存实例已经创建过,那么就取缓存中的实例,不再重新创建。(同一个扩展接口,对应的ExtensionLoader是相同的)
- 默认扩展名ExtensionLoader#cachedDefaultName是怎么读取到值的?
- 解答:加载扩展类时ExtensionLoader#loadExtensionClasses,会读取扩展接口上的@SPI注解中的value属性值,作为默认扩展名ExtensionLoader#cacheDefaultExtensionName
- 封装类是怎么进行缓存的?不放在ExtensionLoader#cachedClasses缓存中吗?
- 解答:封装类是放在ExtensionLoader#cachedWrapperClasses封装类集合中的,而cachedClasses是普通扩展类的缓存,两者进行分开的。
- 解析的配置文件,是怎样进行分类缓存的?
- 解答:在ExtensionLoader#loadClass方法中,会根据是否带有@Adaptive、@Activate等注解,以及是否为封装类进行缓存。
- @Wrapper注解的matches()、mismatches() 匹配和不匹配扩展时怎么使用的?
- 解答:在ExtensionLoader#createExtension中使用封装类对扩展实例进行封装时,会判断需要创建实例的扩展名name,是否在matches列表中且不在mismatches列表中
- ExtensionLoader的类共享变量,什么时候清除的?如:EXTENSION_LOADERS、EXTENSION_INSTANCES?
- 解答:移除扩展类、扩展类的实例,只在ExtensionLoader#resetExtensionLoader中,但根据该方法的描述,仅用于测试。所以存的这两个共享变量不会主动做清除,只有JVM重启,重新发布服务是,才会失效,然后重新创建
- 解析SPI配置文件时,#和空格 是怎么被过滤掉的?
- 解答:在ExtensionLoader#loadResource中会按"#“、”="做分隔,且会去掉前后空格。
- 加载SPI配置文件时,自适应类ExtensionLoader#cachedAdaptiveClass是怎样判断的?
- 解答:自适应扩展类有两种方式产生,一种是在类上加上@Adaptive,并在SPI配置文件中指定,另一种是SPI扩展接口的方法上加上@Adaptive,产生自适应类对应的字符串,并编译成对应的Class对象,最后再创建出实例。
- 自动激活activate的匹配原则是怎样的?
- 解答:自动激活的扩展类包含两类,一类是系统激活的扩展类,通过group、value等进行比较(可通过default来指定系统扩展类),另一类是用户自定义扩展类,只要指定扩展名即可,不需要匹配group、value
- 使用Holder来存储对象,比直接使用对象,好处在哪里?
- 解答:Holder从字面上解释为“持有类”,用于持有目标对象。好处就是对目标对象进行封装和抽象,可以做更多的逻辑。
- 加载策略LoadingStrategy中的overridden是否覆盖,有什么用途?
- 解答:在ExtensionLoader#saveInExtensionClass保存扩展名与扩展类的缓存时,遇到一个扩展名对应多个扩展类时,会根据overridden来判断做覆盖或者抛出异常。
- @Activate#value自动激活中的value是指url中的key,还是扩展名? value值如"key1:value2,key2:value2",是怎么比较的?
- 解答:value指的是url中key对应的value值,是指扩展名。
- SPI配置文件中没有配置扩展名时,怎样创建默认扩展名?如:org.apache.dubbo.common.extension.activate.ActivateExt1文件中的xxx.ActivateExt1Impl1没有扩展名,最终的缓存名字为"activateExt1Impl1"
- 解答:
- 1)判断扩展类型上是否带有注解@Extension,若有去注解中的value值(@Extension已被废弃,不推荐使用)
- 2)获取扩展类的简易名称,如org.apache.dubbo.common.extension.activate.impl.ActivateExt1Impl1的getSimpleName()为"ActivateExt1Impl1"
- a)扩展类的简易名称以扩展接口的简易名称为后缀,如xxxActivateExt1,则把扩展接口的简易名称去掉,即取前半部分的子字符串,得到的扩展名为"xxx"
- b)若不是a)中的形式,则直接将扩展名的简易名称直接小写作为扩展名,如ActivateExt1Impl1对应为“activateext1impl1”
- ExtensionLoader#cacheActivateClass缓存的是扩展名与@Activate对象的映射,在使用时,是怎么找到带有@Activate注解的自动激活扩展类的?
- 解答:自动激活的缓存类型为Map<String, Object> cachedActivates,即缓存了扩展名与@Active注解对象的映射,在获取自动激活的扩展类时,即ExtensionLoader#getActivateExtension会将缓存中@Activate注解配置的值,与输入的参数进行匹配,若匹配成功,则通过@Activate关联扩展名调用getExtension(name),获取到最终的扩展实例
4. 归纳总结
-
不管是自适应扩展类@Adaptive、还是自动激活扩展类@Activate,最终都是找到明确的扩展名,然后通过getExtension(name)找到扩展实例
不过查找扩展名方式有些不同,
a)@Adaptive(value={“key1”,“key2”}),最终是通过 url.getParameter(“key1”,getParameter(“key2”,defaultExtName)) 从url中查找到指定参数对应的扩展名,
b)@Activate有两种形式,一种是自定义激活,另一种是系统自动激活
b.1)自定义激活:ExtensionLoader#getActivateExtension(URL url, String key),直接将url中key对应的值作为扩展名,不需要带上@Activate注解
b.2)自动自动激活:对@Activate注解中的group、value进行比较,满足条件了,就使用@Activate注解对应的扩展名,有两种形式
b.2.1)如@Activate(value={key1,key2}, group=“default_group”),则满足group匹配且,key1、key2出现在url参数的key中。
b.2.2)如@Activate(value={key1:value1,key2:value2}, group=“default_group”),则满足group匹配且,key1、value1或key2、value2任意一个键值对同时出现在url参数中,
即该@Activate注解对应的实例被匹配,然后再到缓存中找到注解对应的扩展名 -
获取实例时,getExtension、getAdaptiveExtension、getActivateExtensionsion获取实例时,都会先调用getExtensionClasses()把扩展类加到缓存中(若已经加载过,则从缓存中取)。getExtensionClasses()中的loadClass()能够分类存储。
-
@Activate自动激活扩展类进行匹配时,group和value条件只要没配置,就表明不使用group、value做限制,即匹配所有。如group没有配置,那么所有group扩展类都能匹配;没有配置value,那么所有value的扩展类都能匹配。
-
创建扩展类实例时,默认是会自动注入依赖的,若不想自动注册依赖,在setXxx方法上加上@DisableInject注解。文章来源:https://www.toymoban.com/news/detail-650865.html
-
一个扩展名只能对应一个扩展类,一个扩展类可以对应多个扩展名,即扩展类与扩展名时是一对多的关系,在配置文件中,扩展名可以配置多个,用逗号分隔。文章来源地址https://www.toymoban.com/news/detail-650865.html
到了这里,关于Dubbo之ExtensionLoader源码解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!