1. Java类加载器资源查找的过程
ClassLoader 类中资源查找有2种
- 一种是 classLoader 对象的实例方法,在 classsLoader 对象的目录范围内查找
// ClassLoader.java 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 { // parent == null, 表示已经找到最顶级 BootStrapClassLoader 加载器 tmp[0] = getBootstrapResources(name); } tmp[1] = findResources(name); return new CompoundEnumeration<>(tmp); }
- 另一种是 ClassLoader 类的静态方法,在 AppClassLoader 的范围,即
classPath
下进行查找// ClassLoader.java public static URL getSystemResource(String name) { ClassLoader system = getSystemClassLoader(); // 返回 AppClassLoader // parent == null, 表示已经找到最顶级 BootStrapClassLoader 加载器 if (system == null) { return getBootstrapResource(name); } return system.getResource(name); }
两种查找资源的方法,都是先递归委托给 parent 的类加载器查找,最后在自己的加载范围内查找。和类加载时的双亲委派一样。
2. SpringFactoriesLoader 扫描资源
SpringFactoriesLoader 会使用 classLoader 对象扫描其可见域下的 spring.properties 实现类,并缓存所有 classLoader 对象和 Map<接口名, List[实现类名]>
的映射关系,其他类加载时,直接通过缓存获取接口的实现类名集合,并用 loadFactories()
反射实例化实现类集合
public final class SpringFactoriesLoader {
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
// interface MultiValueMap<K, V> extends Map<K, List<V>>
// 全局缓存,key: classLoader 对象
// value: Map <String,List<String>> (key: 接口名, value: 实现类名的list )
private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();
//
public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
// 找到接口名下配置的所有实现类类名
List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse);
List<T> result = new ArrayList<>(factoryImplementationNames.size());
for (String factoryImplementationName : factoryImplementationNames) {
// 对 class 反射实例化出对象
result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
}
AnnotationAwareOrderComparator.sort(result);
return result;
}
// 找到接口名下配置的所有实现类类名, 返回 List<String>
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
// 调用 private 方法
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
/**
* 加载 classLoader 对象扫描域下,所有 spring.factpries 文件中配置的 <接口名,List[实现类名]>,放入 cache 中,
* 下次从 cache 中直接通过 classLoader 对象取 <接口名,List[实现类名]>
*/
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
// ClassLoader 两种扫描资源的方法
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
// 解析扫描到的资源文件列表
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
// 解析 properties 文件的每一行,加入 Map<String,List<String>> 中
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
// ...
}
/**
* (1)用 classLoader 加载实现类
* (2)并校验实现类和配置的接口是否是实现关系
* (3)根据实现类名反射实例化对象,
*/
private static <T> T instantiateFactory(String factoryImplementationName, Class<T> factoryType, ClassLoader classLoader) {
try {
// (1)用 classLoader 加载实现类
Class<?> factoryImplementationClass = ClassUtils.forName(factoryImplementationName, classLoader);
// (2)并校验实现类和配置的接口是否是实现关系
if (!factoryType.isAssignableFrom(factoryImplementationClass)) {
throw new IllegalArgumentException(
"Class [" + factoryImplementationName + "] is not assignable to factory type [" + factoryType.getName() + "]");
}
// (3)根据实现类名反射实例化对象,
return (T) ReflectionUtils.accessibleConstructor(factoryImplementationClass).newInstance();
}
// ...
}
}
3. 实现自动配置的 @EnableAutoConfiguration 注解
@EnableAutoConfiguration 注解如下:
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
AutoConfigurationImportSelector.class
该类的 selectImports()
方法使用 SpringFactoriesLoader 扫描并实例化 EnableAutoConfiguration.class
的实现类对象,所以 spring.factories 文件中配置的都是 EnableAutoConfiguration.class
的实现类。如 mybatis starter 的文件内容:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,
getBeanClassLoader());
return configurations;
}