获取 spring 的 bean 方法总结

原创 spring

Spring 是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架,如何在程序中获取 Spring 配置的 bean 呢?

Bean 工厂(com.springframework.beans.factory.BeanFactory)是 Spring 框架最核心的接口,它提供了高级 IoC 的配置机制。BeanFactory 使管理不同类型的 Java 对象成为可能,应用上下文(com.springframework.context.ApplicationContext)建立在 BeanFactory 基础之上,提供了更多面向应用的功能,它提供了国际化支持和框架事件体系,更易于创建实际应用。我们一般称 BeanFactory 为 IoC 容器,而称 ApplicationContext 为应用上下文。但有时为了行文方便,我们也将 ApplicationContext 称为 Spring 容器。

对于两者的用途,我们可以进行简单划分:BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的应用场合我们都直接使用 ApplicationContext 而非底层的 BeanFactory。

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

本文不涉及通过@Resource@Autowired 自动注入,仅仅通过 ApplicationContext 获取 Sping 配置文件中的 Bean。

要获取 XML 中配置的 Bean,最关键的是获取 org.springframework.context.ApplicationContext

第一种:使用 ApplicationContext 实现类 FileSystemXmlApplicationContext 等

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("applicationContext.xml");

或者

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
private ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

这种方式实例化 applicationContext 是非常耗时的,这种方式适用于采用 Spring 框架的独立应用程序,仅仅推荐使用在程序需要通过配置文件手工初始化 Spring 的情况。

ApplicationContext 的主要实现类是 ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext,前者默认从类路径加载配置文件,后者默认从文件系统中装载配置文件

举个栗子:

public class BeanManager
{
    private static ApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml") ;
    public static Object getBean(String beanId)
    {
        return context.getBean(beanId);
    }
}

在 web.xml 中写一个 servlet,自动启动,init 方法中调用一下 BeanManager

public void init() throws ServletException
{
    BeanManager bm = new BeanManager();
    // 可选的,为的是在web应用启动的时候就让spring加载bean配置。
    // 否则会在第一次调用BeanManager的时候加载,影响一次速度。
}

在 Java 代码中使用 BeanManager.getBean(String beanId); 来获得 bean 实例。

第二种:使用工具类 WebApplicationContextUtils

通过 Spring 提供的工具类获取 ApplicationContext 对象,专为 Web 工程定制的方法,推荐 Web 项目中使用。例如:

ServletContext servletContext = request.getSession().getServletContext();
ApplicationContext ac1 = WebApplicationContextUtils.getRequiredWebApplicationContext(ServletContext sc);
ApplicationContext ac2 = WebApplicationContextUtils.getWebApplicationContext(ServletContext sc);
ac1.getBean("beanId");
ac2.getBean("beanId");

通过 javax.servlet.ServletContext 获取到 ApplicationContext 实例对象,这意味着,必须使用到 request、session 等等。

这样,就不能把 ApplicationContext 对象设置为成员变量。需要在每个具体的方法中通过 request、session 等获取到 ServletContext 再获取 ApplicationContext 实例。

因此,此方法仅仅推荐使用在可以获取到 ServletContext 对象的 Web 项目中,并且不需要将 ApplicationContext 对象定义为成员变量的情况下。

注意:当使用 WebApplicationContextUtils 获取 ApplicationContext 实例时,需要在 web.xml 配置文件中添加 org.springframework.web.context.ContextLoaderListener 监听器,否则获取不到 ApplicationContext 对象,返回null

配置文件:web.xml

<!-- ContextLoaderListener自动注入applicationContext,通过WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext())获取Spring配置文件加载位置 -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/appContext.xml,/WEB-INF/spring/appInterceptor.xml</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

第三种:继承自抽象类 ApplicationObjectSupport

抽象类 ApplicationObjectSupport 提供 getApplicationContext() 方法,可以方便的获取到 ApplicationContext。Spring 初始化时,会通过该抽象类的 setApplicationContext(ApplicationContext context) 方法将 ApplicationContext 对象注入。

第四种:继承自抽象类 WebApplicationObjectSupport

通过继承 org.springframework.web.context.support.WebApplicationObjectSupport 使用 getWebApplicationContext() 获取到 org.springframework.web.context.WebApplicationContext。

由于 Web 应用比一般的应用拥有更多的特性,因此 WebApplicationContext 扩展了 ApplicationContext。WebApplicationContext 定义了一个常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,在上下文启动时,WebApplicationContext 实例即以此为键放置在 ServletContext 的属性列表中,因此我们可以直接通过以下语句从 Web 容器中获取 WebApplicationContext:

WebApplicationContext wac = (WebApplicationContext)servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

第五种:实现接口 ApplicationContextAware

实现该接口的 setApplicationContext(ApplicationContext context) 方法,并保存 ApplicationContext 对象。Spring 初始化时,会通过该方法将 ApplicationContext 对象注入。

总结

第三、四、五种方法都需要将类配置在 Spring 配置文件中:

<!-- 假定ApplicationContextTool为继承或者实现了第三、四、五种方法的具体实现类 -->
<bean class="com.twovv.utils.ApplicationContextTool"></bean>

否则将获取不到 ApplicationContext,返回 null

如果觉得这对你有用,请随意赞赏,给与作者支持
评论 0
最新评论