springboot的各个依赖包下,很多都有META-INF/spring.factories这个文件。例如
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.test.springbootdemo.usultestdemo.configration.propertiespropertysource.myconfiguretation.MyCommandRunable,\ com.test.springbootdemo.usultestdemo.configration.propertiespropertysource.myconfiguretation.MyDisposableBeanConfigureration,\ com.test.springbootdemo.usultestdemo.configration.propertiespropertysource.myconfiguretation.MyInitBeanConfigureration,\ com.test.springbootdemo.usultestdemo.configration.propertiespropertysource.myconfiguretation.MyApplicationContextAware
通过内容可以知道spring.factories定义了一些对象。实际上spring.factories的作用就是做上下文初始化,加载配置文件中的bean到Ioc容器,加载配置项等。springboot执行时或扫描所有的META-INF/spring.factories的内容,会将classLoader加载类路径下的所有spring.factories的配置内容,loadSpringFactories方法将返回一个key=接口名,value=实现类集合的Map结构。
在我们的springboot项目中执行run()方法后,就开始进入内容的初始化过程。
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//获取所有的org.springframework.boot.SpringApplicationRunListeners实现类,这里我们也可以使用spring.factories自定义实现类。
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//自定义监听器加载配置信息和系统环境变量
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
//获取所有spring.factories自定义实现,根据type值找到对应的 class 的全限定名称列表
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//执行自定义spring.fatories中的类(Bean初始化类,环境变量初始化类)的指定方法
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
//一些程序启动就要执行的的任务,包括spring.fatories中定义的key为EnableAutoConfiguration, j接口CommandLineRunner的实现类。
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, listeners, exceptionReporters, ex);
throw new IllegalStateException(ex);
}
listeners.running(context);
return context;
}
对象获取到并实例化之后之后,refreshContext(context);会执行自定义spring.fatories中的类(Bean初始化类,环境变量初始化类)的指定方法。callRunners(context, applicationArguments);一些程序启动就要执行的的任务,包括spring.fatories中定义的key为EnableAutoConfiguration, 接口CommandLineRunner的实现类等。
getSpringFactoriesInstances和createSpringFactoriesInstances方法。
public class SpringApplication {
private Collection getSpringFactoriesInstances(Class type) {
return getSpringFactoriesInstances(type, new Class>[] {});
}
// 获取Spring工厂
private Collection getSpringFactoriesInstances(Class type,
Class>[] parameterTypes, Object... args) {
// 获取ClassLoader
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
// 定义class数组,即返回值 names 是所有 classpath 下面的 META-INF/spring.factories 中定义的父节点
Set names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 内部循环初始化 names的构造函数,获取实例实例对象
List instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
// 创建Spring工厂实例
private List createSpringFactoriesInstances(Class type, Class>[] parameterTypes,
ClassLoader classLoader, Object[] args, Set names) {
List instances = new ArrayList<>(names.size());
// 遍历实例对象的全限定名
for (String name : names) {
try {
// 加载该类,通过指定的classloader加载对应的类获取对应的Class对象
Class> instanceClass = ClassUtils.forName(name, classLoader);
// 断言是否为该接口的实现类
Assert.isAssignable(type, instanceClass);
// 获取构造方法
Constructor> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
// 实例化该类
T instance = (T) BeanUtils.instantiateClass(constructor, args);
// 添加到结果集当中
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
}
SpringFactoriesLoader类是解析所有Spring.factories实现。方法主要是loadFactoryNames()和loadSpringFactories()
public abstract class SpringFactoriesLoader {
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
private static final Map> cache = new ConcurrentReferenceHashMap<>();
// 加载工厂
public static List loadFactoryNames(Class> factoryClass, @Nullable ClassLoader classLoader) {
// 获取类名称(图4)
String factoryClassName = factoryClass.getName();
// 根据类名称获取需要加载的工厂类名称
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
// 通过加载所有 classpath 下面的 META-INF/spring.factories文件,扫描加载类
private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
// 从cache获取实例的结果集 当是Null表示当前的cache是空的;cache 实现 new ConcurrentReferenceHashMap<>()
MultiValueMap result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
// 获取所有 classpath 下面的 META-INF/spring.factories 中的资源 urls
// 当classLoader为非空的时候调用getResouurces方法获取
// 当classLoader为空的时候调用ClassLoader.getSystemResouurces方法获取
Enumeration urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
// 循环处理 urls中的元素,获取元素
while (urls.hasMoreElements()) {
// 获取元素 url地址
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
// 解析文件 把文件变成配置属性
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
// 循环解析并把结果放入result
for (Map.Entry, ?> entry : properties.entrySet()) {
// 类名列表
List factoryClassNames = Arrays.asList(
StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
//记录所有的key和对应的value集合
result.addAll((String) entry.getKey(), factoryClassNames);
}
}
// 缓存类加载器和文件解析器的结果集
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
}
在获取到所有的接口之后,就会调用getSpringFactoriesInstances()创建接口的实现类。
spring.factories就像是工厂一样配置了大量的接口对应的实现类,我们通过这些配置 + 反射处理就可以拿到相应的实现类。这种类似于插件式的设计方式,只要引入对应的jar包,那么对应的spring.factories就会被扫描到,对应的实现类也就会被实例化,如果不需要的时候,直接把jar包移除即可。
https://www.cnblogs.com/zhangjianbin/p/6322476.html
https://www.cnblogs.com/huojg-21442/articles/12335457.html