目录

  • 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);
    }

}