Spring——ApplicationContext & Bean的生命周期

关于ApplicationContext和BeanFactory

如果使用ApplicationContext,则配置的Bean如果scope属性是singleton,那么当容器被加载时,这些Bean就会被实例化。好处是可以预先加载,速度快;缺点是耗内存。

如果使用BeanFactory,则当你实例化该对象的时候,配置的Bean不会被马上实例化,当你使用的时候才被实例化。BeanFacotry会延迟加载所有的Bean。这样的好处是节约内存,缺点是速度。

一般没有特殊要求,应当使用ApplicationContext

ApplicationContext是Spring更加高级的容器,功能非常强大:

  • 1.提供文本解析工具,包括对国际化的支持

  • 2.提供载入文件资源的通用方法,如图片。

  • 3.可以向注册为监听器的bean发送事件。

ApplicationContext三种经常用到的实现:

  • 1.ClassPathXmlApplicationContext:从类路径中加载。

  • 2.FileSystemXmlApplicationContext:从文件系统加载。

  • 3.XmlWebApplicationContext:从Web系统中加载。

Bean的生命周期

Bean被加载到容器中时,他的生命周期就开始了:

  • 1.容器寻找Bean的定义信息并实例化。

当我们的程序加载beans.xml(或spring-config.xml)文件的时候,把我们的Bean(前提是scope=singleton)实例化到内存。

  • 2.使用依赖注入,Spring按Bean定义信息配置Bean的所有属性。

使用setter方法设置属性,所以,Bean类必须为属性提供setter方法。

  • 3.若Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。

setBeanName(String s)方法可以获取正在实例化的Bean的ID号。

比如下例,我们让入门【Spring——入门】案例中的UserService类实现BeanNameAware接口,然后重写其setBeanName(String s)方法

package com.gavin.service;

import org.springframework.beans.factory.BeanNameAware;

public class UserService  implements BeanNameAware{
    private String name;
    private ByeService byeService;

    public UserService() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public ByeService getByeService() {
        return byeService;
    }

    public void setByeService(ByeService byeService) {
        this.byeService = byeService;
    }

    public void sayHello() {
        System.out.println("Hello, " + name);
        byeService.sayBye();
    }

    @Override
    public void setBeanName(String s) {
        System.out.println("当前Bean的ID号为:" + s);
    }
}

此时运行TestMain主方法后,结果如下:

这里写图片描述

可以看到,我们在UserService类中获取到了当前类的ID,这个ID正是我们配置在Spring配置文件中的ID。

  • 4.若Bean实现了BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身。

setBeanFactory(BeanFactory beanFactory)方法可以给我们传递工厂自身。

BeanNameAware类似,实现这个接口可以让我们在Bean对象中获取当前的工厂。

  • 5.若Bean实现了ApplicationContextAware接口,工厂调用setApplicationContext()方法传入上下文。

  • 6.若BeanPostProcessor(Bean后置处理器)和Bean关联,则它们的postProcessBeforeInitialization()方法被调用。

后置处理器BeanPostProcessor有点类似于Web中的Filter。

public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        System.out.println("postProcessBeforeInitialization方法被调用");
        return o;
    }

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        System.out.println("postProcessAfterInitialization方法被调用");
        return o;
    }
}

在beans.xml中的配置:

<bean id="myBeanPostProcessory"  class="com.gavin.beanlife.MyBeanPostProcessor"/>

假设配置了后置处理器,不管是实例化哪个Bean,都会先调用 postProcessBeforeInitialization方法。

后置处理器的应用需求有:

  • 记录每个对象被实例化的时间
  • 过滤每个调用对象的IP
  • 给所有对象添加一个属性,获取其他的函数(所谓AOP,面向切面编程,针对所有对象编程)

  • 7.若Bean实现了InitializingBean接口,则会调用afterPropertiesSet()方法。

该方法会在自己定制的初始化方法和后置处理器的postProcessAfterInitialization()方法之前调用。

  • 8.如果自己定制了init-method,则调用自己定制的初始化方法
<bean id="personService" init-method="init" class="com.gavin.beanlife.PersonService">
    <property name="name" value="Gavin"/>
</bean>
  • 9.最后,若有BeanPostProcessor和Bean关联,则它们的postProcessAfterInitialization()方法被调用。

  • 10.使用Bean

  • 11.容器关闭

  • 12.当容器关闭后,若实现了DisposableBean接口,则会调用destroy()方法。

  • 13.如果自己定制了销毁方法,配置了destroy-method,则会调用自己定制的销毁方法,配置如下:

<bean id="personService" init-method="init" destroy-method="destroy" class="com.gavin.beanlife.PersonService">
    <property name="name" value="Gavin"/>
</bean>

【注意】在实际开发中可能并不需要上述所有的步骤。根据需要即可。一般的步骤:1->2->6->9->10->11


问题:通过BeanFactory来获取Bean,和通过ApplicationContext来获取Bean,生命周期是否一样的?

答案:不一样,BeanFactory获取Bean的生命周期简单得多!

如下两幅图对比:

这里写图片描述

这里写图片描述

猜你喜欢

转载自blog.csdn.net/gggavin/article/details/79521806