Spring容器中获取Bean实例的七种方式(附实战源码)

写作说明
一:写作原因

首先解释一下写这篇博文的原因,因为在使用spring框架的过程中获取bean是非常常见的操作,但是网上非常的博文大多承自一家之言,因此很多可操作性上并不强,本文是通过自己实战,亲自尝试之后提供的几种方案,供大家一起学习探讨。

二:源码出处

本文出自原创,如果您转发请注明出处,另本文提供的测试代码为chapter-1-springmvc-quickstart中的单元测试类BeanUtilTest如果有需要的可自行下载

实现方式

本文一共提供七种实现方式:

一:使用BeanFactory直接获取(不推荐)

使用BeanFactory从工厂中直接获取Bean实例,但是XmlBeanFactory类已经废弃,因此不建议使用,测试代码如下:

    /**
     * 方式一:XmlBeanFactory已经废弃不建议使用
     */
    @Test
    public void getBeanTest1() {
        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
        UserInfo userInfo = (UserInfo) beanFactory.getBean("userInfo");
        System.out.println(userInfo);
    }
二:在初始化时保存ApplicationContext对象

可以在初始化的时候保存ApplicationContext对象,然后通过这个对象获取Bean,测试代码如下:

    /**
     * 方式二:使用ClassPathXmlApplicationContext获取ApplicationContext
     */
    @Test
    public void getBeanTest2() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserInfo userInfo = (UserInfo) applicationContext.getBean("userInfo");
        System.out.println(userInfo);
    }
三:继承自抽象类ApplicationObjectSupport

可以继承抽象类ApplicationObjectSupport并将自己继承的类注入到Spring容器中,示例代码如下:

    /**
     * 方法三:继承ApplicationObjectSupport来获取ApplicationContext,
     * 注意:需要把自己继承的类注入到Spring
     */
    @Test
    public void getBeanTest3() {
        ApplicationContextUtil2 applicationContextUtil2 = (ApplicationContextUtil2) ApplicationContextUtil.getBean("applicationContextUtil2");
        UserInfo userInfo = (UserInfo) applicationContextUtil2.getBean("userInfo");
        System.out.println(userInfo);
    }

其中ApplicationContextUtil2的代码如下所示:

public class ApplicationContextUtil2 extends ApplicationObjectSupport {

    /**
     * 通过bean的id获取bean对象
     * @param beanName
     * @return
     */
    public Object getBean(String beanName){
        return super.getApplicationContext().getBean(beanName);
    }

}

最后莫忘了将Bean注入到Spring容器中,通过注解,或者配置均可,本示例通过配置实现

    <!-- 测试获取bean的方式,继承ApplicationObjectSupport需要先注入这个类 -->
    <bean id="applicationContextUtil2" class="com.leo.util.ApplicationContextUtil2"></bean>
四:继承自抽象类WebApplicationObjectSupport

可以继承抽象类WebApplicationObjectSupport并将自己继承的类注入到Spring容器中,示例代码如下:

    /**
     * 方法四:继承WebApplicationObjectSupport来获取ApplicationContext,
     * 注意:需要把自己继承的类注入到Spring,同时需要添加@WebAppConfiguration注解,否则会找不到web容器
     */
    @Test
    public void getBeanTest4() {
        ApplicationContextUtil3 applicationContextUtil3 = (ApplicationContextUtil3) ApplicationContextUtil.getBean("applicationContextUtil3");
        UserInfo userInfo = (UserInfo) applicationContextUtil3.getBean("userInfo");
        System.out.println(userInfo);
    }

其中ApplicationContextUtil3 的示例代码如下:

public class ApplicationContextUtil3 extends WebApplicationObjectSupport{

    /**
     * 通过bean的id获取bean对象
     * @param beanName
     * @return
     */
    public Object getBean(String beanName){
        return super.getWebApplicationContext().getBean(beanName);
    }

}

最后莫忘了将Bean注入到Spring容器中,通过注解,或者配置均可,本示例通过配置实现

    <!-- 测试获取bean的方式,继承WebApplicationObjectSupport需要先注入这个类 -->
    <bean id="applicationContextUtil3" class="com.leo.util.ApplicationContextUtil3"></bean>
五:使用Spring提供的工具类WebApplicationContextUtils

使用Spring提供的工具类WebApplicationContextUtils来获取WebApplicationContext对象,这个方法很常见于SpringMVC构建的web项目中,测试代码如下所示:

    /**
     * 方法五:使用WebApplicationContextUtils提供的方法获取ApplicationContext对象
     */
    @Test
    public void getBeanTest5(){
        //模拟ServletContext上下文,不然会出现空指针异常
        MockServletContext sc = new MockServletContext("");
        sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM, "/applicationContext.xml");
        ServletContextListener listener = new ContextLoaderListener();
        ServletContextEvent event = new ServletContextEvent(sc);
        listener.contextInitialized(event);

        //使用WebApplicationContextUtils的getRequiredWebApplicationContext方法
        WebApplicationContext webApplicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
        UserInfo userInfo = (UserInfo) webApplicationContext.getBean("userInfo");
        System.out.println(userInfo);
        //使用WebApplicationContextUtils的getWebApplicationContext方法
        WebApplicationContext webApplicationContext2 = WebApplicationContextUtils.getWebApplicationContext(sc);
        UserInfo userInfo2 = (UserInfo) webApplicationContext2.getBean("userInfo");
        System.out.println(userInfo2);
    }
六:实现ApplicationContextAware接口

通过实现ApplicationContextAware接口,在Spring容器启动的时候将ApplicationContext注入进去,从而获取ApplicationContext对象,这种方法也是常见的获取Bean的一种方式,测试代码如下:

    /**
     *方法六:实现ApplicationContextAware接口获取ApplicationContext
     */
    @Test
    public void getBeanTest6(){
        UserInfo userInfo2 = (UserInfo) ApplicationContextUtil.getBean("userInfo");
        System.out.println(userInfo2);
    }

其中ApplicationContextUtil的实现如下:

public class ApplicationContextUtil implements ApplicationContextAware{
    private static ApplicationContext applicationContext;

    /**
     * 通过bean的id获取bean对象
     * @param beanName
     * @return
     */
    public static Object getBean(String beanName){
        return applicationContext.getBean(beanName);
    }

    /**
     * 根据bean的id和类型获取bean对象
     * @param beanName
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getBean(String beanName,Class<T> clazz){
        return clazz.cast(getBean(beanName));
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
七:使用ContextLoader提供的getCurrentWebApplicationContext方法

使用ContextLoader提供的getCurrentWebApplicationContext方法提供的方法也是常用的获取WebApplicationContext的一种方法,这个方法常见于SpringMVC实现的web项目中。测试代码如下:

    /**
     * 方法七:使用ContextLoader的getCurrentWebApplicationContext方法获取WebApplicationContext
     */
    @Test
    public void getBeanTest7() {
        MockServletContext sc = new MockServletContext("");
        sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM, "/applicationContext.xml");
        ServletContextListener listener = new ContextLoaderListener();
        ServletContextEvent event = new ServletContextEvent(sc);
        listener.contextInitialized(event);
        //如果不加上面的模拟创建ServletContext对象,会报空指针异常
        WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
        UserInfo userInfo = (UserInfo) wac.getBean("userInfo");
        System.out.println(userInfo);
    }
好的,我会尽力解释 Spring 容器的启动流程源码。 1. 加载配置文件 Spring 容器启动时,首先会读取配置文件,通常是 `applicationContext.xml`。配置文件定义了需要被 Spring 管理的 bean,以及它们的依赖关系等信息。 2. 创建 BeanDefinition Spring 容器会解析配置文件,创建对应的 BeanDefinition 对象。BeanDefinition 定义了 bean 的基本信息,如 bean 的类名、scope、依赖关系等等。 3. 注册 BeanDefinition 接下来,Spring 容器将创建的 BeanDefinition 注册到 BeanDefinitionRegistry BeanDefinitionRegistry 是一个接口,它定义了注册、查询、删除 BeanDefinition 的方法。 4. 实例Bean 接下来,Spring 容器将开始实例bean。Spring 容器使用反射创建 bean 的实例,然后根据配置文件的信息对 bean 进行初始化。 5. 填充属性值 在 bean 实例化之后,Spring 容器会开始填充属性值。Spring 容器会根据配置文件的信息,自动为 bean 填充属性值。这些属性可以是基本类型、引用类型、集合类型等等。 6. 调用 BeanPostProcessor 在填充完属性值之后,Spring 容器会调用 BeanPostProcessor 的方法。BeanPostProcessor 是一个接口,它定义了在 bean 实例化和初始化过程的回调方法。通过实现 BeanPostProcessor,我们可以在 bean 实例化和初始化的过程做一些自定义的操作。 7. 初始化 Bean 在填充完属性值和调用 BeanPostProcessor 之后,Spring 容器会调用 bean 的初始化方法。初始化方法可以是 init-method 指定的方法,也可以是实现了 InitializingBean 接口的 afterPropertiesSet() 方法。 8. 注册销毁方法 当 bean 的生命周期结束时,Spring 容器会调用它的销毁方法。销毁方法可以是 destroy-method 指定的方法,也可以是实现了 DisposableBean 接口的 destroy() 方法。 以上就是 Spring 容器启动流程的大概过程。其BeanDefinition、BeanPostProcessor、InitializingBean、DisposableBean 等接口和类都是 Spring 框架提供的,它们为我们提供了更加灵活的配置和扩展方式
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

leo825...

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值