系统初始化器ApplicationContextInitializer
官方对其描述是 Spring容器刷新之前执行的一个回调函数,它的作用是向 Springboot容器中注册属性。
案例:通过系统初始化器向springboot容器中注入属性的方法。
方法1:
@Order(1)
public class FirstInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// 获取环境变量
ConfigurableEnvironment environment = applicationContext.getEnvironment();
// 自定义一个属性
Map<String,Object> map = new HashMap<>();
map.put("key1","value1");
MapPropertySource mapPropertySource = new MapPropertySource("firstInitializer",map);
//加入到环境变量的属性中
environment.getPropertySources().addLast(mapPropertySource);
System.out.println("run 第一个初始化器,向springboot容器中注入属性");
}
}
之后,在resources下新建一个META-INF文件夹,放入一个spring.factories(配置文件)(自动装载机制)
org.springframework.context.ApplicationContextInitializer=\
com.example.springbootlearn.initializer.FirstInitializer
验证,新建一个service
@Service
public class TestService implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext= applicationContext;
}
public String test(){
return applicationContext.getEnvironment().getProperty("key1");
}
}
新建一个controller
@RestController
public class HelloController {
@Resource
private TestService testService;
@GetMapping("test")
public String getname(){
return testService.test();
}
}
访问http://127.0.0.1:8080/test 就可以将我们注入的属性打印出来value1.
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.6.6)
run 第一个初始化器,向springboot容器中注入属性
方法2:
建SecondInitializer
@Order(2)
public class SecondInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// 获取环境变量
ConfigurableEnvironment environment = applicationContext.getEnvironment();
// 自定义一个属性
Map<String,Object> map = new HashMap<>();
map.put("key2","value2");
MapPropertySource mapPropertySource = new MapPropertySource("secondInitializer",map);
//加入到环境变量的属性中
environment.getPropertySources().addLast(mapPropertySource);
System.out.println("run 第二个初始化器,向springboot容器中注入属性");
}
}
然后在启动类上改进
@SpringBootApplication
public class SpringbootlearnApplication {
public static void main(String[] args) {
// SpringApplication.run(SpringbootlearnApplication.class, args);
SpringApplication springApplication = new SpringApplication(SpringbootlearnApplication.class);
springApplication.addInitializers(new SecondInitializer());
springApplication.run(args);
}
}
启动后控制台打印:
run 第一个初始化器,向springboot容器中注入属性
run 第二个初始化器,向springboot容器中注入属性
debug断点applicationContext.getEnvironment().getProperty(“key2”);结果value2
方法3:
通过配置
@Order(3)
public class ThirdInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// 获取环境变量
ConfigurableEnvironment environment = applicationContext.getEnvironment();
// 自定义一个属性
Map<String,Object> map = new HashMap<>();
map.put("key3","value3");
MapPropertySource mapPropertySource = new MapPropertySource("thirdInitializer",map);
//加入到环境变量的属性中
environment.getPropertySources().addLast(mapPropertySource);
System.out.println("run 第三个初始化器,向springboot容器中注入属性");
}
}
Application.yml
context:
initializer:
classes: com.example.springbootlearn.initializer.ThirdInitializer
启动:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.6.6)
run 第三个初始化器,向springboot容器中注入属性
run 第一个初始化器,向springboot容器中注入属性
run 第二个初始化器,向springboot容器中注入属性
@order值越小越靠前,但是,第三个初始化器,是放入配置文件中,所以优先打印。
以上三种实现方式:都是通过实现ApplicationContextInitializer接口
只不过后续不同,第一个是通过自动装配spring.factories实现,第二个是主启动类设置进去,第三个是配置文件实现(也可以理解为自动装配。
工厂加载机制SpringFactoriesLoader
它的意思是:
- 框架内部使用通用工厂加载机制(工厂模式)
- 从classpath下多个jar读取文件并初始化类(从各个jar中的META-INF/spring.factories)
- 文件是内容是k-v形式,Properties(内部是hashtable)类型
- key是全限定名(接口,抽象类),value是具体实现,如果是多个实现则用逗号分割。
- example.MyService=example.MyServiceImpl1,example.MyServiceImpl2
其中example.MyService是接口的名称(key), MyServiceImpl1和MyServiceImpl2是两个实现(value)。
- example.MyService=example.MyServiceImpl1,example.MyServiceImpl2
初始化器是如何被springboot发现的?
debug断点,
SpringFactoriesLoader.loadFactoryNames
使用给定的类加载器从"META-INF/spring.factories"加载给定类型的工厂实现的完全限定类名。
setInitializers(getSpringFactoriesInstances(ApplicationContextInitializer.class))的含义就是:
含义就是从spring.factories中key=ApplicationContextInitializer,找到所对应的value值,并将查到的所有全类名实例化,并最后放入到list集合中。
分析方法1的方式
由于方法1它是有spring.factories配置,所以,肯定能加载成功。
方法2的方式:
springApplication.addInitializers(new SecondInitializer());
也可以加载成功
方法3的方式:DelegatingApplicationContextInitializer
一句话总结就是:SpringFactoriesLoader将spring.factories下的所有文件加载出来,并且全部实例化放入一个list集合中。