spring获取已实例化IOC容器中的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稍长一些

要获取XML中配置的Bean,最关键的是获取.springframework.context.ApplicationContext,以下是总结的几种方法

方法一:在初始化时保存ApplicationContext对象
方法二:通过Spring提供的utils类获取ApplicationContext对象
方法三:继承自抽象类ApplicationObjectSupport
方法四:继承自抽象类WebApplicationObjectSupport
方法五:实现接口ApplicationContextAware
方法六:通过Spring提供的ContextLoader

方法一:在初始化时保存ApplicationContext对象
ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml"); 
ac.getBean("beanId");

说明:这种方式适用于采用Spring框架的独立应用程序,需要程序通过配置文件手工初始化Spring的情况。
说明:这种方式适用于采用Spring框架的独立应用程序,需要程序通过配置文件手工初始化Spring的情况。

方法二:通过Spring提供的工具类获取ApplicationContext对象
ApplicationContext ac1 = WebApplicationContextUtils.getRequiredWebApplicationContext(ServletContext sc); 
ApplicationContext ac2 = WebApplicationContextUtils.getWebApplicationContext(ServletContext sc); 
ac1.getBean("beanId"); 
ac2.getBean("beanId");

说明:这种方式适合于采用Spring框架的B/S系统,通过ServletContext对象获取ApplicationContext对象,然后在通过它获取需要的类实例。上面两个工具方式的区别是,前者在获取失败时抛出异常,后者返回null。

方法三:继承自抽象类ApplicationObjectSupport
WebApplicationContext wac = (WebApplicationContext)servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

说明:抽象类ApplicationObjectSupport提供getApplicationContext()方法,可以方便的获取ApplicationContext。

Spring初始化时,会通过该抽象类的setApplicationContext(ApplicationContext context)方法将ApplicationContext 对象注入。

方法四:继承自抽象类WebApplicationObjectSupport

说明:类似上面方法,调用getWebApplicationContext()获取WebApplicationContext

方法五:实现接口ApplicationContextAware(推荐)

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

以下是实现ApplicationContextAware接口方式的代码,前面两种方法类似:

public class SpringContextUtil implements ApplicationContextAware { 

    // Spring应用上下文环境 
    private static ApplicationContext applicationContext; 

    /** 
     * 实现ApplicationContextAware接口的回调方法,设置上下文环境 
     * 
     * @param applicationContext 
     */ 
    public void setApplicationContext(ApplicationContext applicationContext) { 
        SpringContextUtil.applicationContext = applicationContext; 
    } 

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

    /** 
     * 获取对象 
     * 
     * @param name 
     * @return Object
     * @throws BeansException 
     */ 
    public static Object getBean(String name) throws BeansException { 
        return applicationContext.getBean(name); 
    } 
}

虽然,spring提供的后三种方法可以实现在普通的类中继承或实现相应的类或接口来获取spring 的ApplicationContext对象,但是在使用是一定要注意实现了这些类或接口的普通java类一定要在Spring 的配置文件applicationContext.xml文件中进行配置。否则获取的ApplicationContext对象将为null。

方法六:通过Spring提供的ContextLoader(有使用条件)
/**
 * 获取Spring容器中Bean实例的工具类
 */
public class SpringBeanUtils {

    /**
     * 根据bean的名称获取相应类型的对象,使用泛型,获得结果后,不需要强制转换为相应的类型
     * 此方法适用在web开发中获取spring的bean
     * @param clazz bean的类型,使用泛型
     * @return T类型的对象
     */
    public static <T> T getBeanByGeneric(Class<T> clazz) {
        WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
        T bean = wac.getBean(clazz);
        return bean;
    }
}

最后提供一种不依赖于servlet,不需要注入的方式。但是需要注意一点,在服务器启动时,Spring容器初始化时,不能通过以下方法获取Spring 容器,细节可以查看spring源码org.springframework.web.context.ContextLoader。

方法七:实现接口BeanFactoryAware(与ApplicationContextAware类似)

自定义一个工具类,实现自BeanFactoryAware接口,接口的方法是setBeanFactory,我们实现它,并让其为我们服务,因为Spring在load自己的时候会将上下文环境填充进来。

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.stereotype.Service;

/**
 * 获取Spring容器中Bean实例的工具类
 */
@Service
public class SpringBeanUtils implements BeanFactoryAware {

    private static BeanFactory beanFactory;

    /**
     * 注入sring的BeanFactory实例
     */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        SpringBeanUtils.beanFactory = beanFactory;
    }

    /**
     * 根据bean的名称获取相应类型的对象
     * 
     * @param beanName bean的名称
     * @return Object类型的对象
     */
    public static Object getBean(String beanName) {
        return beanFactory.getBean(beanName);
    }

    /**
     * 根据bean的Class获取相应类型的对象
     * 
     * @param beanName bean的名称
     * @return Object类型的对象
     */
    public static <T> T getBean(Class<T> clazz) {
        return beanFactory.getBean(clazz);
    }
}

题外:

使用 Class.forName(String s)时,传的是类的全路径(包含包)
上面几种获取bean的。传的是bean的名称(首字母小写)
针对接口,需要获取相关的实现类,应为注解是在实现类上的

Leave a Reply

Your email address will not be published. Required fields are marked *

lWoHvYe 无悔,专一