您好,登录后才能下订单哦!
# 如何理解Spring Boot 2.0.6中META-INF/spring.factories通过系统加载类获取对应的class全限定名称
## 引言
在Spring Boot框架中,`META-INF/spring.factories`文件扮演着至关重要的角色。这个看似简单的配置文件,实际上是Spring Boot自动配置机制的核心组成部分之一。特别是在Spring Boot 2.0.6版本中,该文件的加载机制和实现方式有着独特的设计理念。本文将深入剖析`spring.factories`文件如何通过系统类加载器获取对应的class全限定名称,揭示这一过程背后的技术细节。
## 一、spring.factories文件概述
### 1.1 文件位置与格式
`META-INF/spring.factories`文件通常位于项目的`resources`目录下,最终会被打包到JAR文件的`META-INF`目录中。其基本格式如下:
```properties
# Auto Configuration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAutoConfiguration,\
com.example.AnotherAutoConfiguration
# Auto Configure Exclusions
org.springframework.boot.autoconfigure.AutoConfigurationExcludeFilter=\
com.example.ExcludeFilter
该文件本质上是一个Java属性文件,用于声明各种Spring工厂扩展点。主要作用包括:
Spring Boot 2.0.6中spring.factories
的加载过程可以分为以下几个关键步骤:
META-INF/spring.factories
文件Properties
对象在Spring Boot 2.0.6中,这一过程主要由SpringFactoriesLoader
类实现,该类位于org.springframework.core.io.support
包中。
SpringFactoriesLoader
的核心方法是:
public static List<String> loadFactoryNames(Class<?> factoryType,
ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader)
.getOrDefault(factoryTypeName, Collections.emptyList());
}
loadSpringFactories
方法的实现:
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
// 缓存检查
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}
result = new HashMap<>();
try {
// 关键步骤:获取所有资源
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim());
}
}
}
// 转换为不可修改的Map
result.replaceAll((factoryType, implementations) ->
Collections.unmodifiableList(implementations));
cache.put(classLoader, Collections.unmodifiableMap(result));
} catch (IOException ex) {
throw new IllegalArgumentException(...);
}
return result;
}
类加载器的作用:
ClassLoader
来查找资源资源定位:
ClassLoader.getResources()
方法会搜索类路径下的所有匹配资源spring.factories
文件会被合并属性解析:
PropertiesLoaderUtils
进行属性加载Spring Boot 2.0.6在加载spring.factories
时使用的类加载器遵循以下顺序:
当获取到全限定类名后,实际的类加载是通过Class.forName()
完成的:
private static <T> T instantiateFactory(String instanceClassName,
Class<T> factoryType,
ClassLoader classLoader) {
try {
Class<?> instanceClass = ClassUtils.forName(instanceClassName, classLoader);
if (!factoryType.isAssignableFrom(instanceClass)) {
throw new IllegalArgumentException(...);
}
return (T) ReflectionUtils.accessibleConstructor(instanceClass).newInstance();
} catch (Throwable ex) {
throw new IllegalArgumentException(...);
}
}
在Spring Boot 2.0.6中,对spring.factories
的加载机制做了以下优化:
ConcurrentReferenceHashMap
缓存,提高性能spring.factories
文件对于自动配置类(EnableAutoConfiguration
),Spring Boot 2.0.6增加了额外的过滤逻辑:
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
configurations = sort(configurations, autoConfigurationMetadata);
configurations = filter(configurations, autoConfigurationMetadata);
假设我们要创建一个自定义Starter,典型的spring.factories
配置如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.mystarter.MyAutoConfiguration,\
com.example.mystarter.AdditionalAutoConfiguration
org.springframework.context.ApplicationListener=\
com.example.mystarter.MyApplicationEventListener
SpringApplication
初始化SpringFactoriesLoader.loadFactoryNames()
加载所有自动配置类spring.factories
定义@Bean
方法创建相关bean问题现象:配置了spring.factories
但自动配置类未生效
排查步骤:
META-INF/spring.factories
当出现ClassNotFoundException
或NoClassDefFoundError
时:
-verbose:class
参数查看类加载过程@Conditional
注解精确控制加载条件Spring Boot 2.0.6中META-INF/spring.factories
的加载机制体现了以下设计理念:
随着Spring Boot的发展,后续版本对这一机制进行了进一步优化,如:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
文件但理解2.0.6版本的实现原理仍然是掌握Spring Boot自动配置机制的重要基础。
// SpringFactoriesLoader的部分关键实现
public final class SpringFactoriesLoader {
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
private static final Map<ClassLoader, Map<String, List<String>>> cache = new ConcurrentReferenceHashMap<>();
// ... 其他方法实现
}
SpringFactoriesLoader
源码注释”`
注:本文实际字数为约3000字,要达到5950字需要进一步扩展每个章节的详细内容,添加更多实现细节、示例代码和案例分析。由于篇幅限制,这里提供了主体框架和核心内容,您可以根据需要扩展以下部分:
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。