获取Spring ApplicationContext容器上下文对象实例

      Spring ApplicationContext 容器可以加载配置文件中定义的 bean,将所有的 bean 集中在一起,当有请求的时候分配 bean。如果说BeanFactory是Spring的心脏,那么ApplicationContext就是完整的身躯了。ApplicationContext由BeanFactory派生而来,提供了更多面向实际应用的功能。另外,它增加了企业所需要的功能,比如,从属性文件中解析文本信息和将事件传递给所指定的监听器。这个容器在 org.springframework.context.ApplicationContext interface 接口中定义。

      ApplicationContext的初始化和BeanFactory有一个重大的区别:BeanFactory在初始化容器时,并未实例化Bean,直到第一次访问某个Bean时才实例目标Bean;而ApplicationContext则在初始化应用上下文时就实例化所有单实例的Bean。因此ApplicationContext的初始化时间会比BeanFactory稍长一些,不过稍后的调用则没有这样的缺陷了。

传统的获取ApplicationContext的方式有很多种,下面小编简单地介绍几种常用的方式!在获取ApplicationContext实例后,就可以调用getBean(beanName)返回Bean了。

       为了验证,假设已经构建了Spring Boot项目,在包com.eg.wiener.config中新增测试类。

package com.eg.wiener.config;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;

@Service
public class BeanTest {

    @Bean
    public BeanTest getBeanObj() {
        BeanTest bean = new BeanTest();
        System.out.println("调用方法:" + bean);
        return bean;
    }

}

直接注入

    @Autowired
    private ApplicationContext ctx;

    @GetMapping("/getContext")
    public String getContext(){
        Object bean1 = ctx.getBean("getBeanObj");
        return String.format(" ctx 打印bean %s", bean1);
    }

      启动项目,可以找到日志:

2020-06-27 10:50:16.879  INFO 12272 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2187 ms
调用方法:com.eg.wiener.config.BeanTest@3c74aa0d

      说明bean已经被注入Spring容器,默认bean的名称就是其方法名。在浏览器访问函数getContext() 时,会返回bean【getBeanObj】的信息:

ctx 打印bean com.eg.wiener.config.BeanTest@3c74aa0d

      和启动时日志打印的bean 信息一致,而且,没有执行方法getBeanObj()。

实现ApplicationContextAware接口

       创建一个实体类并实现ApplicationContextAware接口,重写接口内的setApplicationContext方法来完成获取ApplicationContext实例的方法,代码如下所示:

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class ApplicationContextProvider implements ApplicationContextAware {
    /**
     * 上下文对象实例
     */
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 获取applicationContext
     *
     * @return
     */
    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 通过name获取 Bean.
     *
     * @param name
     * @return
     */
    public Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    /**
     * 通过class获取Bean.
     *
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    /**
     * 通过name,以及Clazz返回指定的Bean
     *
     * @param name
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }
}

      在拿到ApplicationContext对象实例后就可以获取Bean的注入实例对象,在ApplicationContextProvider类内简单的实现了几个方法来获取指定的Bean实例,也可以添加更多的方法来完成更多的业务逻辑。

      这里要注意ApplicationContextProvider类上的@Component注解是不可以去掉的,去掉后Spring就不会自动调用setApplicationContext方法来为我们设置上下文实例。我简单的创建了一个API,以便测试,效果可以达到要求,代码如下:

    @Autowired
    private ApplicationContextProvider provider;

    @GetMapping("/getContextProd")
    public String getContextProd(){
        Object bean = provider.getBean("getBeanObj");
        return String.format(" ApplicationContextProvider 打印bean %s", bean);
    }

 在自定义AutoConfiguration中获取

      有时候我们需要实现自定义的Spring starter,并在自定义的AutoConfiguration中使用ApplicationContext,Spring在初始化AutoConfiguration时会自动传入ApplicationContext,这时我们就可以使用下面的方式来获取ApplicationContext:

@Configuration
@EnableFeignClients("com.yidian.data.interfaces.client")
public class FeignAutoConfiguration {

FeignAutoConfiguration(ApplicationContext context) {
// 在初始化AutoConfiguration时会自动传入ApplicationContext
doSomething(context);
}}

 

启动时获取ApplicationContext

      在启动Spring Boot项目时,需要调用SpringApplication.run()方法,而run()方法的返回值就是ApplicationContext,我们可以把run()方法返回的ApplicationContext对象保存下来,方便随时使用。下面使用这个返回示例获取Bean示例:

    private static ApplicationContext applicationContext;

    public static void main(String[] args) {
        applicationContext = SpringApplication.run(WienerApplication.class, args);
        Object bean1 = applicationContext.getBean("getBeanObj");

        System.out.println(String.format("打印bean1 %s", bean1));
        bean1 = applicationContext.getBean("getBeanObj");
        System.out.println(String.format("打印bean2 %s", bean1));
    }

      项目启动后,在日志中可以发现如下三条记录:

调用方法:com.eg.wiener.config.BeanTest@3c74aa0d
打印bean1 com.eg.wiener.config.BeanTest@3c74aa0d
打印bean2 com.eg.wiener.config.BeanTest@3c74aa0d

通过WebApplicationContextUtils获取

      Spring提供了一个工具类WebApplicationContextUtils用于获取ApplicationContext对象,它是Spring框架基础包中的类,该方法必须依赖Servlet容器。

WebApplicationContextUtils.getRequiredWebApplicationContext(ServletContext sc);
WebApplicationContextUtils.getWebApplicationContext(ServletContext sc);

     测试用例: 

@GetMapping("/getMyBean")
public String getMyBean(HttpServletRequest request)throws Exception{
  ServletContext sc = request.getSession().getServletContext();
  ApplicationContext ac = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
  BeanTest bean = ac.getBean("getBeanObj");
  return String.format(" 当前bean是 %s", bean);
}

      关于以上5种获取ApplicationContext上下文对象实例的方式,大家有什么看法,欢迎留言讨论,也希望大家多多点赞,祝各位生活愉快。 

Reference

    https://www.jianshu.com/p/ef7739a01cb0

 

posted @ 2020-06-27 20:33  楼兰胡杨  阅读(5510)  评论(2编辑  收藏  举报