Spring Boot 工厂加载机制 SpringFactoriesLoader
Posted on 2020-02-06 20:12 work hard work smart 阅读(2165) 评论(1) 编辑 收藏 举报SpringFactoriesLoader 介绍
框架内部使用的通用工厂加载机制
从classpath下多个jar包特定的位置读取文件并初始化类
文件内容必须是kv形式,即properties类型
key是全限定名(抽象类|接口)、value是实现,多个用逗号分隔
SpringFactoriesLoader作用
SpringBoot框架中从类路径jar包中读取特定文件实现扩展类的载入
将所有Jar中的spring.factories(A.jar(spring.factories),
B.jar(spring.factories),
C.jar(spring.factories)
......
)载入 Spring Boot框架
SpringFactoriesLoader在什么时候加载系统初始化器呢?
查看源码
从启动类开始
SpringApplication.run(Sb2Application.class, args);
1、进入run方法
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) { return run(new Class<?>[] { primarySource }, args); } public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); } public SpringApplication(Class<?>... primarySources) { this(null, primarySources); }
2、进入SpringApplication构造函数
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
3、然后进入setInitializers方法
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
4、进入getSpringFactoriesInstances方法
5、然后进入loadFactoryNames方法
6、然后进入loadFactoryNames方法
上面代码对应loadFactories的流程图
可以发现FACTORIES_RESOURCE_LOCATION的值为"META-INF/spring.factories"。 这就是为什么我们前面要在META-INF文件夹下创建spring.factories 文件的原因。
获得所有Jar包下的META-INF/spring.factories文件
classLoader.getResources(FACTORIES_RESOURCE_LOCATION)
通过以下过程,将初始化器注入到容器当中
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryClassName = ((String) entry.getKey()).trim();
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryClassName, factoryName.trim());
}
}
如下图,Debug显示的所有系统初始化器
names返回7个初始化器
7、然后实例化这7个初始化器
通过反射进行实例化
8、通过setInitializers将初始化器实例注入到spring容器中
public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) { this.initializers = new ArrayList<>(); this.initializers.addAll(initializers); }
作者:Work Hard Work Smart
出处:http://www.cnblogs.com/linlf03/
欢迎任何形式的转载,未经作者同意,请保留此段声明!