Seata-common模块,EnhancedServiceLoader类解析
1. 简单介绍下 java spi思想
- 为某个接口寻找服务实现的机制
- 解耦(接口调用与服务提供者解耦)
- 基于接口编程
2. Seata spi核心类EnhancedServiceLoader分析
使用例子:
定义接口类 com.test.Hello
实现类A com.test.AHello
实现类B com.test.BHello
在resources目录下新建META-INF/services目录,并添加接口全路径名文件com.test.Hello 文件中写入实现类全路径名

调用EnhancedServiceLoader.load(Hello.class) 获取实现类。
2.1最重要的几个方法解析
//加载所有的扩展类loadAllExtensionClass(loader);//获取默认扩展类ExtensionDefinition defaultExtensionDefinition = getDefaultExtensionDefinition();//获取指定的扩展类ExtensionDefinition cachedExtensionDefinition = getCachedExtensionDefinition(activateName);//获取扩展类实例getExtensionInstance(cachedExtensionDefinition, loader, argTypes, args);
2.2加载默认扩展类
private S loadExtension(ClassLoader loader, Class[] argTypes,
Object[] args) {
try {
loadAllExtensionClass(loader);
//默认获取list最后一个元素,list已按order值排序
ExtensionDefinition defaultExtensionDefinition = getDefaultExtensionDefinition();
//对扩展类实例化
return getExtensionInstance(defaultExtensionDefinition, loader, argTypes, args);
} catch (Throwable e) {
if (e instanceof EnhancedServiceNotFoundException) {
throw (EnhancedServiceNotFoundException)e;
} else {
throw new EnhancedServiceNotFoundException(
"not found service provider for : " + type.getName() + " caused by " + ExceptionUtils
.getFullStackTrace(e));
}
}
}
2.3 加载扩展类并缓存
//加载所有的扩展类
private List<Class> loadAllExtensionClass(ClassLoader loader) {
List<ExtensionDefinition> definitions = definitionsHolder.get();
if (definitions == null) {
synchronized (definitionsHolder) {
definitions = definitionsHolder.get();
if (definitions == null) {
//类加载器查找所有定义的扩展类
definitions = findAllExtensionDefinition(loader);
definitionsHolder.set(definitions);
}
}
}
return definitions.stream().map(def -> def.getServiceClass()).collect(Collectors.toList());
}
2.4 加载文件,对实例排序
//加载文件路径
private static final String SERVICES_DIRECTORY = "META-INF/services/";
private static final String SEATA_DIRECTORY = "META-INF/seata/";
private List<ExtensionDefinition> findAllExtensionDefinition(ClassLoader loader) {
List<ExtensionDefinition> extensionDefinitions = new ArrayList<>();
try {
loadFile(SERVICES_DIRECTORY, loader, extensionDefinitions);
loadFile(SEATA_DIRECTORY, loader, extensionDefinitions);
} catch (IOException e) {
throw new EnhancedServiceNotFoundException(e);
}
//After loaded all the extensions,sort the caches by order
if (!nameToDefinitionsMap.isEmpty()) {
for (List<ExtensionDefinition> definitions : nameToDefinitionsMap.values()) {
Collections.sort(definitions, (def1, def2) -> {
int o1 = def1.getOrder();
int o2 = def2.getOrder();
return Integer.compare(o1, o2);
});
}
}
if (!extensionDefinitions.isEmpty()) {
Collections.sort(extensionDefinitions, (definition1, definition2) -> {
int o1 = definition1.getOrder();
int o2 = definition2.getOrder();
return Integer.compare(o1, o2);
});
}
//返回排序后的扩展类集合
return extensionDefinitions;
}
2.5 总结下Java类加载
ExtClassLoader AppClassLoader 均继承URLClassLoader
- AppClassLoader 应用类加载器,又称为系统类加载器
- ExtClassLoader 扩展类加载器 默认加载JAVA_HOME/jre/lib/ext/目录下的所有jar包;ExtClassLoader初始化过程中,将父类加载器设置成了null, 因为 BootstrapClassLoader是 C++编写,对于 Java 本身来说它是不存在的。所以此处设置null表示它的父类加载器就是启动类加载器
- BootstrapClassLoader 启动类加载器 顶层的类加载器 JDK中的核心ClassLoader类库,如:rt.jar、resources.jar、charsets.jar等
下图loadFile方法中 loader.getResources(fileName),ClassLoader.getSystemResources(fileName) 区别 :
- getSystemResources先获取系统类加载器,获取不到则启动类加载器查资源, 最后调用system.getResources(name)
class.getResource和classloader.getResource区别:
- class的getResource不加“/”,会从class这个类所在的路径开始往下搜索资源,如果加上“/”,会从工程的根目录,也就是截图里的target/classes这个路径下开始搜索资源
- classloader的getResource不加“/”,会通过双亲委派向上加载,未加载到,则通过当前类加载器加载classpath根目录资源;如果加上“/”,表示Boot ClassLoader中的加载范围,因为这个类加载器是C++实现的,所以加载范围为null
public Enumeration<URL> getResources(String name) throws IOException {
@SuppressWarnings("unchecked")
Enumeration<URL>[] tmp = (Enumeration<URL>[]) new Enumeration<?>[2];
if (parent != null) {
tmp[0] = parent.getResources(name);
} else {
tmp[0] = getBootstrapResources(name);
}
tmp[1] = findResources(name);
return new CompoundEnumeration<>(tmp);
}
public static Enumeration<URL> getSystemResources(String name)
throws IOException
{
ClassLoader system = getSystemClassLoader();
if (system == null) {
return getBootstrapResources(name);
}
return system.getResources(name);
}
当前类加载器加载文件路径, 实例化后写入集合
//查找目录下文件
private void loadFile(String dir, ClassLoader loader, List<ExtensionDefinition> extensions)
throws IOException {
String fileName = dir + type.getName();
Enumeration<java.net.URL> urls;
if (loader != null) {
//此类所在的包下取资源
urls = loader.getResources(fileName);
} else {
urls = ClassLoader.getSystemResources(fileName);
}
if (urls != null) {
while (urls.hasMoreElements()) {
java.net.URL url = urls.nextElement();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), Constants.DEFAULT_CHARSET))) {
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 {
ExtensionDefinition extensionDefinition = getUnloadedExtensionDefinition(line, loader);
if (extensionDefinition == null) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("The same extension {} has already been loaded, skipped", line);
}
continue;
}
extensions.add(extensionDefinition);
} catch (LinkageError | ClassNotFoundException e) {
LOGGER.warn("Load [{}] class fail. {}", line, e.getMessage());
}
}
}
} catch (Throwable e) {
LOGGER.warn("load clazz instance error: {}", e.getMessage());
}
}
}
}
2.6 反射加载class
private ExtensionDefinition getUnloadedExtensionDefinition(String className, ClassLoader loader)
throws ClassNotFoundException {
//Check whether the definition has been loaded
if (!isDefinitionContainsClazz(className, loader)) {
//实例化class
Class<?> clazz = Class.forName(className, true, loader);
String serviceName = null;
Integer priority = 0;
Scope scope = Scope.SINGLETON;
LoadLevel loadLevel = clazz.getAnnotation(LoadLevel.class);
if (loadLevel != null) {
//获取注解定义参数,order为排序值,scope默认单例
serviceName = loadLevel.name();
priority = loadLevel.order();
scope = loadLevel.scope();
}
ExtensionDefinition result = new ExtensionDefinition(serviceName, priority, scope, clazz);
classToDefinitionMap.put(clazz, result);
if (serviceName != null) {
CollectionUtils.computeIfAbsent(nameToDefinitionsMap, serviceName, e -> new ArrayList<>())
.add(result);
}
return result;
}
return null;
}
声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/221962.html