一、ExtensionLoader是什么?作用有哪些?
ExtensionLoader是服务发现、动态加载机制的具体实现。
ExtensionLoader的作用:
1、加载所有打上了@SPI注解的接口,生成动态适配器类,并根据配置动态选择具体的实现类。
2、实现简单ioc,对实现类的依赖属性进行setter注入(就是调用setXXX方法实现赋值)
3、对具体实现类进行包装wrapper,比如Protocol实现,每种具体的Protocol实现都经过 ProtocolListenerWrapper、
PtotocolFilterWrapper、QosProtocolWrapper的联合包装,用以实现服务监听、过滤。
二、重要属性
//spi加载的路径
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/";
//??缓存每个打了SPI注解的接口类对应的ExtensionLoader实例
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();
//缓存每个实现类的实例,key:实现类Class,value:实现类实例
private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>();
//缓存接口实现类对应的别名,比如DubboProtocol类的别名是dubbo,key:实现类Class,value:别名
private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<>();
//缓存别名对应的实现类,key:别名,value:实现类Class。特别注意:这里的value是Class,不是实例对象
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>()
//??
private final Map<String, Object> cachedActivates = new ConcurrentHashMap<>();
//缓存实现类的实例对象信息,key:把别名,value:实现类实例对象的包装类
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();
//SPI接口实现类实例,这个实例可能是动态生成的接口适配器类,也可能是打了@Adaptive注解的类
private final Holder<Object> cachedAdaptiveInstance = new Holder<>();
//每个SPI接口类的Adaptive实现类。想要参与SPI机制的接口类上都要打上@SPI注解,每个接口通常都有多种实现。
//业务方如果指定实现,便用业务方指定的实现类;否则,使用默认的实现。通常默认的实现类别名在@SPI("dubbo")中
//指定。那dubbo是如何支持动态选择实现类的呢?通常,会针对SPI接口生成一个适配器类,比如Protocol的适配器类
//Protocol$Adaptive。在适配器中会根据业务参数进行选择具体实现类(实现类加载过后会被缓存到map中)
//但如果某个实现类打上了@Adaptive注解,那么这个类就是默认实现,不会再为接口生成适配器类
private volatile Class<?> cachedAdaptiveClass = null;
//每个接口类的默认实现类的别名
private String cachedDefaultName;
//包装类,接口实现类的包装类,比如Protocol接口的包装类:ProtocolListenerWrapper、PtotocolFilterWrapper、QosProtocolWrapper
private Set<Class<?>> cachedWrapperClasses;
三、重要方法
1、ExtensionLoader() : 构造方法
private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
1)这里可以看出每个SPI接口都有一个ExtensionFactory实现与之对应。每个封装了SPI的ExrtensionLoader都保存着
一个objectFactory对象,而objectFactory对象都是ExtensionFactory接口的@Adaptive实现,即
AdaptiveExtensionFactory。
2)那么这个ExtensionFactory的作用是什么呢?ExtensionLoader在进行ioc,给对象设置依赖的属性值时,
objectFactory负责找到依赖的属性值,这个依赖值可能是Spring体系中的bean,也可能是其他的SPI扩展类。
其实ExtensionFactory接口有三个实现类,分别AdaptiveExtensionFactory、SpiExtensionFactory、
SpringExtensionFactory。AdaptiveExtensionFactory是默认实现,但是没有具体的实现逻辑,它是依赖
SpiExtensionFactory和SpringExtensionFactory完成功能的。
//factories是个列表,列表中只有两个元素,SpiExtensionFactory和SpringExtensionFactory
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;
}
2、getAdaptiveExtension():获取动态适配器
//每个SPI接口都有多种实现类,通常都会把对应的实现类实例后缓存起来(map),然后在构造一个接口的适配器类,
//在适配器类中根据业务参数从缓存中动态选择具体的实现,用以完成业务功能
public T getAdaptiveExtension() {
//判断是否实例化过接口的Adaptive实现(要么是接口的适配器类,要么是接口的@Adaptive实现类)
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {
if (createAdaptiveInstanceError == null) {
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
//创建SPI接口的Adaptive实现
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;
}
3、createAdaptiveExtension():创建SPI接口的Adaptive实现
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);
}
}
Notes:getAdaptiveExtensionClass方法是真正实现的地方,injectExtension方法用以完成ioc功能
4、getAdaptiveExtensionClass():获取SPI接口的Adaptive实现的类信息
private Class<?> getAdaptiveExtensionClass() {
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
//如果SPI接口类没有@Adaptive实现类,则要创建适配器类
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
5、getExtensionClasses():加载SPI接口的各个实现类
private Map<String, Class<?>> getExtensionClasses() {
//判断是否加载过SPI接口的实现类
Map<String, Class<?>> classes = cachedClasses.get();
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
//加载SPI接口的实现类
classes = loadExtensionClasses();
cachedClasses.set(classes);
}
}
}
return classes;
}
6、loadExtensionClasses():加载SPI接口的实现类
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;
}
7、loadDirectory():加载SPI接口的实现类
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);
}
}
8、loadResource():加载SPI接口的实现类
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);
}
}
这个功能要结合下面的截图看一下,如下图,实现类是以“别名=类全路径名”,根据类全路径名加载类
9、loadClass():实例化加载的实现类
//类的加载其实在loadResource方法中已经完成了,生成的clazz入参
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.");
}
//判断该实现类是否有Adaptive注解,是的话就将该实现类赋值给cachedAdaptiveClass
if (clazz.isAnnotationPresent(Adaptive.class)) {
cacheAdaptiveClass(clazz);
//判断该实现类是不是包装类,是的话将该实现类添加入cachedWrapperClasses集合中
} 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) {
//缓存实例类到cachedNames中
cacheName(clazz, n);
//缓存实例类到extensionClasses中,最终是赋值给cachedClasses
saveInExtensionClass(extensionClasses, clazz, n);
}
}
}
}
10、createAdaptiveExtensionClass():创建适配器类
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);
}
这里以Protocol接口的适配器类举例,详见:
https://note.youdao.com/web/#/file/WEB707524014b5f25df84f77a3a8fafedfa/note/WEB4da5d1bb4a6fac5bbd99d32155e11efa/
11、injectExtension():对实现类进行ioc操作
//简单ioc,调用实现类的setXXX方法,为其注入依赖的类
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
for (Method method : instance.getClass().getMethods()) {
if (isSetter(method)) {
if (method.getAnnotation(DisableInject.class) != null) {
continue;
}
Class<?> pt = method.getParameterTypes()[0];
if (ReflectUtils.isPrimitives(pt)) {
continue;
}
try {
String property = getSetterProperty(method);
//这里就是AdaptiveExtensionFactory起作用的地方,找到依赖的类
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;
}
12、getExtension(String name):根据业务参数获取对应的实现类
public T getExtension(String name) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Extension name == null");
}
if ("true".equals(name)) {
return getDefaultExtension();
}
//从cachedInstances中查找name对应的实现类
final Holder<Object> holder = getOrCreateHolder(name);
Object instance = holder.get();
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
//若name对应的实现类不存在,则创建实现类
instance = createExtension(name);
holder.set(instance);
}
}
}
return (T) instance;
}
//缓存SPI实现类的包装类Holder。从cachedInstances中查找,有则返回,无则创建
private Holder<Object> getOrCreateHolder(String name) {
Holder<Object> holder = cachedInstances.get(name);
if (holder == null) {
cachedInstances.putIfAbsent(name, new Holder<>());
holder = cachedInstances.get(name);
}
return holder;
}
13、createExtension(String name):根据业务参数创建SPI实现类
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) {
//缓存中若没有name对应的实现类实例,则通过反射生成
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
injectExtension(instance);
//这个是精华了,如果SPI接口有相应的包装类,则在此处会对原始invoker进行层层包装,链式调用
//以Protocol为例,它的包装类有三个,分别是:
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);
}
}
//判断cachedClasses中是否有有效元素,若有则直接返回,若没有则调用loadExtensionClasses方法,
//加载一遍SPI接口对应的实现类。以Protocol接口为例,这个cachedClasses中呢应该有DubboProtocol、
//RestProtocol、RegistryProtocol等类的class信息
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;
}