Dubbo拓展类的特性
(1)自动包装:ExtensionLoader在加载拓展时,如果发现这个拓展类包含其他拓展点作为构造函数的参数,这个拓展类就会被认为是Wrapper类。
这是一种装饰器模式,把通用的抽象逻辑进行封装或对子类进行增强,让子类可以更加专注具体的实现。
(2)自动加载:如果某个拓展类是另一个拓展点类的成员属性,并且拥有setter方法,那么框架也会自动注入对应的拓展点实例。
(3)自适应:使用@Adaptive注解可以动态通过URL中的参数来确定要使用哪个具体的实现类,从而解决自动加载中的实例注入问题。
(4)自动激活:使用@Activate注解,可以标记对应的拓展点默认被激活启用。该注解可以通过传入不同的参数,设置拓展点在不同的条件下被自动激活。主要使用场景是某个拓展点的多个实现类需要同时启用。
ExtensionFactory
ExtensionFactory有三个子类实现,包括:AdaptiveExtensionFactory、SpiExtensionFactory和SpringExtensionFactory。其中AdaptiveExtensionFactory优先级最高,因为AdaptiveExtensionFactory类上面带有@Adaptive注解。
AdaptiveExtensionFactory 的构造方法会先构造一个ExtensionFactory的拓展加载器,然后从资源文件获取SpiExtensionFactory和SpringExtensionFactory放入factories中。AdaptiveExtensionFactory#getExtension就是调用SpiExtensionFactory#getExtension和SpringExtensionFactory#getExtension获取拓展类。SpringExtensionFactory先根据名称从IOC容器中获取拓展类,获取不到,再根据类型从IOC容器获取。SpiExtensionFactory针对带有@SPI注解的接口,返回Adapative拓展实现类(如果不存在带有@Adaptive的实现类,就由Dubbo通过javassist自动生成)。
@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) {
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
}
}
ExtensionLoader
ExtensionLoader#getExtensionLoader先从集合中获取指定Class类型的拓展加载器,如果获取不到就创建一个,并放入集合中。
//拓展加载器集合
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
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;
}
ExtensionLoader的构造方法会去判断传入的Class类型是否是ExtensionFactory,如果不是就会获取ExtensionFactory的Adaptive自适应拓展类。
//对象工厂
private final ExtensionFactory objectFactory;
//实例化一个ExtensionLoader的时候会去创建一个对象工厂
private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
ExtensionLoader#getAdaptiveExtension用于获取自适应的拓展类。会先从一个Holder对象中获取实例,如果获取不到,对Holder对象进行同步,再次判断实例是否为空,如果为空,调用ExtensionLoader#createAdaptiveExtension进行创建。
private final Holder<Object> cachedAdaptiveInstance = new Holder<>();
public T getAdaptiveExtension() {
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {
if (createAdaptiveInstanceError == null) {
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
instance = createAdaptiveExtension();
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
}
}
}
} else {
throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
}
}
return (T) instance;
}
通过Class.newInstance方法实例化一个对象,并通过ExtensionLoader#injectExtension替实例对象的属性赋值(依赖注入)。
private T createAdaptiveExtension() {
try {
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
}
}
先调用ExtensionLoader#getExtensionClasses获取一个带有@Adaptive注解的拓展类。如果获取不到,再调用ExtensionLoader#createAdaptiveExtensionClass生成一个。
private Class<?> getAdaptiveExtensionClass() {
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
获取cacheClasses对象,获取不到,调用ExtensionLoader#loadExtensionClasses获取。
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>();
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;
}
在给定的资源文件夹目录下查找指定名称的类的拓展类。
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 Map<String, Class<?>> loadExtensionClasses() {
cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap<>();
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;
}
如果给定的type类型带有@SPI注解,将属性value值缓存为默认的拓展名。如果value值经过逗号分隔之后有多个,抛出More than 1 default extension name on extension异常。
private void cacheDefaultExtensionName() {
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation != null) {
String value = defaultAnnotation.value();
if ((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];
}
}
}
}
根据给定的文件夹路径,获取文件夹下面指定Class类型的资源信息。遍历每一个文件,读取文件中的每一个KeyValue信息。
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) {
String fileName = dir + type;
try {
Enumeration<java.net.URL> urls;
ClassLoader classLoader = findClassLoader();
if (classLoader != null) {
urls = classLoader.getResources(fileName);
} else {
urls = ClassLoader.getSystemResources(fileName);
}
if (urls != null) {
while (urls.hasMoreElements()) {
java.net.URL resourceURL = urls.nextElement();
loadResource(extensionClasses, classLoader, resourceURL);
}
}
} catch (Throwable t) {
logger.error("Exception occurred when loading extension class (interface: " +
type + ", description file: " + fileName + ").", t);
}
}
读取资源文件每一行内容。每一行查找#字符(注释字符)的位置,截取位置0到#字符前一个位置,再获取拓展类别名(等号前面的值)和全限定类名(等号后面的值),利用Class.forName(String name, boolean initialize, ClassLoader loader)获得字符串参数中指定的类,并初始化该类。
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
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) {
try {
String name = null;
int i = line.indexOf('=');
if (i > 0) {
name = line.substring(0, i).trim();
line = line.substring(i + 1).trim();
}
if (line.length() > 0) {
loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
}
} 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);
}
}
判断clazz是否是给定type(实例化ExtensionLoader传入的类型)的子类,如果不是抛出异常。
判断clazz是否带有@Adaptive注解,如果有,调用ExtensionLoader#cacheAdaptiveClass方法缓存这个类到cachedAdaptiveClass集合。
判断clazz是否是包装wrapper类,如果是,添加到包装类集合。
判断资源文件的拓展名为空,根据clazz名称和type名称获取拓展名,如果拓展名依然为空,抛出No such extension name for the class异常。
拓展名根据逗号分割,第一个拓展名缓存到cachedActivates集合。遍历每一个拓展名,缓存到cachedNames集合和extensionClasses集合。
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
if (!type.isAssignableFrom(clazz)) {
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)) {
cacheAdaptiveClass(clazz);
} else if (isWrapperClass(clazz)) {
cacheWrapperClass(clazz);
} else {
clazz.getConstructor();
if (StringUtils.isEmpty(name)) {
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);
if (ArrayUtils.isNotEmpty(names)) {
cacheActivateClass(clazz, names[0]);
for (String n : names) {
cacheName(clazz, n);
saveInExtensionClass(extensionClasses, clazz, n);
}
}
}
}
缓存Adaptive拓展类。如果超过1个子类带有@Adaptive注解就会抛出More than 1 adaptive class found异常。
private void cacheAdaptiveClass(Class<?> clazz) {
if (cachedAdaptiveClass == null) {
cachedAdaptiveClass = clazz;
} else if (!cachedAdaptiveClass.equals(clazz)) {
throw new IllegalStateException("More than 1 adaptive class found: "
+ cachedAdaptiveClass.getClass().getName()
+ ", " + clazz.getClass().getName());
}
}
判断是否是包装类。clazz是否具有只有给定type类型一个入参的构造方法,如果有,说明是包装wrapper类;如果没有,说明不是包装wrapper类。
private boolean isWrapperClass(Class<?> clazz) {
try {
clazz.getConstructor(type);
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
缓存包装类。实例化一个HashSet集合用于存储包装类。
private void cacheWrapperClass(Class<?> clazz) {
if (cachedWrapperClasses == null) {
cachedWrapperClasses = new ConcurrentHashSet<>();
}
cachedWrapperClasses.add(clazz);
}
判断给定clazz类型是否带有@Extension注解,如果有,直接返回@Extension注解的value属性值。如果没有,获取给定clazz的名称,如果是以type名字结尾的,就截取除去type名称的部分(如:SpiExtensionFactory-ExtensionFactory=Spi),转成小写后返回。
private String findAnnotationName(Class<?> clazz) {
org.apache.dubbo.common.Extension extension = clazz.getAnnotation(org.apache.dubbo.common.Extension.class);
if (extension == null) {
String name = clazz.getSimpleName();
if (name.endsWith(type.getSimpleName())) {
name = name.substring(0, name.length() - type.getSimpleName().length());
}
return name.toLowerCase();
}
return extension.value();
}
判断给定的clazz是否带有@Activate注解,如果有,缓存到cachedActivates集合。如果没有,判断是否带有ailibaba的@Activate注解,如果有,缓存到cachedActivates集合。
private void cacheActivateClass(Class<?> clazz, String name) {
Activate activate = clazz.getAnnotation(Activate.class);
if (activate != null) {
cachedActivates.put(name, activate);
} else {
// support com.alibaba.dubbo.common.extension.Activate
com.alibaba.dubbo.common.extension.Activate oldActivate = clazz.getAnnotation(com.alibaba.dubbo.common.extension.Activate.class);
if (oldActivate != null) {
cachedActivates.put(name, oldActivate);
}
}
}
判断cacheNames集合中是否存在指定的clazz的key,如果不存在,添加到集合。
private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<>();
private void cacheName(Class<?> clazz, String name) {
if (!cachedNames.containsKey(clazz)) {
cachedNames.put(clazz, name);
}
}
将指定的clazz放入extensionClasses集合。
private void saveInExtensionClass(Map<String, Class<?>> extensionClasses, Class<?> clazz, String name) {
Class<?> c = extensionClasses.get(name);
if (c == null) {
extensionClasses.put(name, clazz);
} else if (c != clazz) {
throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + name + " on " + c.getName() + " and " + clazz.getName());
}
}
获取实例类全部的方法,判断是否是符合条件的set方法,如果是,通过ExtensionFactory获取一个拓展类。
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 {
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;
}
假设方法的名称是setName,会返回name。去掉set,将set后面的首字母转成小写返回。
private String getSetterProperty(Method method) {
return method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
}
判断一个方法是否以set开头,是否只有一个入参,是否是publie方法,如果都是,返回true。
private boolean isSetter(Method method) {
return method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers());
}
如果没有找到一个带有@Adaptive注解的拓展类,就生成一个。默认用JavassistCompiler进行生成。Compiler带有@Adaptive的实现类是AdaptiveCompiler,AdaptiveCompiler#complie方法是调用SPI(“javassist”)实现的。
private Class<?> createAdaptiveExtensionClass() {
String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
ClassLoader classLoader = findClassLoader();
org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
添加了SPI注解,默认实现是JavassistCompiler。
@SPI("javassist")
public interface Compiler {
Class<?> compile(String code, ClassLoader classLoader);
}
AdaptiveCompiler#compile先获取Compiler的拓展加载器,如果没有指定调用哪一个拓展类,就调用SPI注解默认值的拓展类JavassistCompiler。
通过javassist自动生成和编译一个Adaptive类。
@Adaptive
public class AdaptiveCompiler implements Compiler {
private static volatile String DEFAULT_COMPILER;
public static void setDefaultCompiler(String compiler) {
DEFAULT_COMPILER = compiler;
}
@Override
public Class<?> compile(String code, ClassLoader classLoader) {
Compiler compiler;
ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
String name = DEFAULT_COMPILER; // copy reference
if (name != null && name.length() > 0) {
compiler = loader.getExtension(name);
} else {
compiler = loader.getDefaultExtension();
}
return compiler.compile(code, classLoader);
}
}
ExtensionLoader#getExtension根据指定的名称获取拓展类。如果传入的拓展类名称是true,会返回默认拓展类。如果cachedInstances中无法获取到指定名称的实例,调用ExtensionLoader#createExtension创建实例。
public T getExtension(String name) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Extension name == null");
}
if ("true".equals(name)) {
return getDefaultExtension();
}
final Holder<Object> holder = getOrCreateHolder(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;
}
从class缓存中获取指定名称的class,从EXTENSION_INSTANCES中根据指定的类获取实例,如果获取不到,实例化一个。调用ExtensionLoader#injectExtension替实例的所有set方法依赖注入。如果有包装类,用包装类装饰原来的实例。
private T createExtension(String name) {
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
injectExtension(instance);
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (CollectionUtils.isNotEmpty(wrapperClasses)) {
for (Class<?> wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
type + ") couldn't be instantiated: " + t.getMessage(), t);
}
}
参考
[Dubbo拓展点加载机制] (https://blog.csdn.net/u012734723/article/details/107467689)
《深入理解Apache Dubbo与实战》