目录
- ApplicationContext工具类 | bean的获取
- 保存应用上下文引用
- 在引导类中保存run()方法返回的应用上下文
- 使用应用上下文初始化器 ApplicationContextInitializer
- 使用应用监听器 ApplicationListener
- 使用应用上下文的Aware接口 ApplicationContextAware
ApplicationContext、ApplicationContextInitializer、ApplicationListener、ApplicationContextAware 都是spring提供的,但通常都是直接使用springboot,所以直接介绍在springboot中的使用。
ApplicationContext工具类 | bean的获取
有时候需要通过应用上下文获取一些资源,比如获取容器中的bean实例,可以 @Autowired 注入 ApplicationContext 直接操作应用上下文,但太粗暴了,应用上下文这种核心、重量级的实例,怎么允许到处操作、使用,风险大、容易搞出问题。
通常是封装一个从上下文中获取资源的工具类,在应用启动时保存应用上下文的引用,在工具类中通过上下文的引用来进行操作。
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
/**
* 操作应用上下文 ApplicationContext 的工具类
*/
public class ApplicationContextUtils {
/**
* 应用上下文的引用
*/
private static ApplicationContext applicationContext;
/**
* 设置应用上下文的引用
*/
public static void setApplicationContext(ApplicationContext applicationContext) {
ApplicationContextUtils.applicationContext = applicationContext;
}
/**
* 获取应用上下文的引用
*/
public static ApplicationContext getApplicationContext() {
return ApplicationContextUtils.applicationContext;
}
/**
* 通过name获取bean
*
* @param name beanName
* @return 获取到的bean
*/
public static Object getBean(String name) {
return applicationContext.getBean(name);
}
/**
* 通过class获取bean
*
* @param clazz bean的Class对象
* @return 获取到的bean
*/
public static <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
/**
* 通过name+class获取bean
*
* @param name beanName
* @param clazz bean的Class对象
* @return 获取到的bean
*/
public static <T> T getBean(String name, Class<T> clazz) {
return applicationContext.getBean(name, clazz);
}
}
并没有提供设置、更改应用上下文中资源的方法,要配置上下文应该在应用启动时就配置,应用启动后一般不允许再修改上下文的配置。
下面介绍在应用启动时保存应用上下文引用的常见方式。
保存应用上下文引用
介绍5种常见的方式,使用其中一种即可
在引导类中保存run()方法返回的应用上下文
最简单的保存方式
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
//实例run()方法会返回创建的应用上下文
ConfigurableApplicationContext applicationContext = SpringApplication.run(DemoApplication.class, args);
ApplicationContextUtils.setApplicationContext(applicationContext);
}
}
使用应用上下文初始化器 ApplicationContextInitializer
自定义的 ApplicationContextInitializer
//实现 ApplicationContextInitializer<ConfigurableApplicationContext>,重写 initialize() 方法
public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
//保存应用上下文的引用
ApplicationContextUtils.setApplicationContext(configurableApplicationContext);
}
}
修改引导类的main()方法如下
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
//创建spring容器
SpringApplication application = new SpringApplication(DemoApplication.class);
//添加应用上下文的初始化器。此时已经生成了应用上下文,应用上下文初始化器可以对应用上下文做进一步处理
application.addInitializers(new MyApplicationContextInitializer());
//启动容器
application.run(args);
}
}
说明
自定义的应用上下文初始化器、应用监听器都不建议用 spring.factories 方式进行配置,普通springboot项目可以用 spring.factories 方式配置初始化器、监听器,但构建在springboot基础上的springcloud有2个上下文:bootstrap、application,这2个上下文都会加载 spring.factories,从而出现重复调用初始化器、监听器的情况,尽量使用spring.factories之外的方式进行配置
使用应用监听器 ApplicationListener
应用上下文创建后,引用不会变化,可以监听启动过程中的一些指定事件,在回调方法中保存上下文的引用,比如
- 应用上下文的 ContextRefreshedEvent、ContextStartedEvent 事件
- 默认运行监听器发布的 ApplicationContextInitializedEvent、ApplicationPreparedEvent、ApplicationStartedEvent、ApplicationReadyEvent 事件
监听其中一种即可
@Component //放到容器中
public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
//保存应用上下文的引用
ApplicationContextUtils.setApplicationContext(event.getApplicationContext());
}
}
可以用 @Component 放到容器中,也可以在引导类中手动添加监听器,使用其中一种即可
//创建spring容器
SpringApplication application = new SpringApplication(DemoApplication.class);
//添加应用监听器
application.addListeners(new MyApplicationListener());
//启动容器
application.run(args);
使用应用上下文的Aware接口 ApplicationContextAware
自定义的 ApplicationContextAware
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component //放到容器中
public class MyApplicationContextAware implements ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//保存应用上下文的引用
ApplicationContextUtils.setApplicationContext(applicationContext);
}
}