11--Spring Bean的生命周期

版权声明:如有转载,请标明出处,谢谢合作! https://blog.csdn.net/lyc_liyanchao/article/details/82391647

上一篇温习了Spring实例化bean的三种方式,接下来我们继续温习一下Spring的基础知识Bean的生命周期,在了解Bean的生命周期之前应该对Bean的作用域有所了解。

1.Bean的作用域
  • singleton:单例bean,单例Bean只会在每个Spring IoC容器中存在一个实例,而且其完整生命周期完全由Spring容器管理.对于所有获取该Bean的操作Spring容器将只返回同一个Bean.在Spring内部通过HashMap来维护单例bean的缓存
  • prototype:原型bean,Spring不会缓存该类型bean的实例,每次向Spring容器请求获取Bean都返回一个全新的Bean
  • request:每个请求需要容器创建一个全新Bean,该类型作用于Web类型的Spring容器
  • session:表示每个会话需要容器创建一个全新Bean,该类型作用于Web类型的Spring容器
  • globalSession:类似于session作用域,只是其用于portlet环境的web应用.如果在非portlet环境将视为session作用域
  • 总结:以上就是spring中bean的作用域,其中singleton,prototype属于Spring bean的基本作作用域,request,session,globalSession属于web应用环境的作用域,必须有web应用环境的支持
2.Bean的生命周期

了解bean的生命周期对于接下来要分析源码非常重要,而且面试经常会问到spring的生命周期

  • 引用spring官方文档说明
Bean factory implementations should support the standard bean lifecycle interfaces as far as possible. The full set of initialization methods and their standard order is1.BeanNameAware's setBeanName
    2.BeanClassLoaderAware's setBeanClassLoader
    3.BeanFactoryAware's setBeanFactory
    4.EnvironmentAware's setEnvironment
    5.EmbeddedValueResolverAware's setEmbeddedValueResolver
    6.ResourceLoaderAware's setResourceLoader (only applicable when running in an application context)
    7.ApplicationEventPublisherAware's setApplicationEventPublisher (only applicable when running in an application context)
    8.MessageSourceAware's setMessageSource (only applicable when running in an application context)
    9.ApplicationContextAware's setApplicationContext (only applicable when running in an application context)
    10.ServletContextAware's setServletContext (only applicable when running in a web application context)
    11.postProcessBeforeInitialization methods of BeanPostProcessors
    12.InitializingBean's afterPropertiesSet
    13.a custom init-method definition
    14.postProcessAfterInitialization methods of BeanPostProcessors

On shutdown of a bean factory, the following lifecycle methods apply:

    1.postProcessBeforeDestruction methods of DestructionAwareBeanPostProcessors
    2.DisposableBean's destroy
    3.a custom destroy-method definition

都是英文,而且都是spring内部接口或者类,方法的使用,再用图片来说明一下

  • 图解

Spring生命周期

在前面的博客中我们已经分析了Spring容器的启动,只是一个开端,接下来要分析的东西才是重点和难点…如果对Spring生命周期毫无了解的人,这张图令人费解,接下来我们简单分析一下图中的流程,每个步骤的作用,再通过一个简单的例子,让大家对bean的生命周期有所了解

  1. IoC容器启动
  2. 实例化bean
  3. 如果Bean实现了BeanNameAware接口,则调用setBeanName(String name)返回beanName,该方法不是设置beanName,而只是让Bean获取自己在BeanFactory配置中的名字
  4. 如果Bean实现BeanFactoryAware接口,会回调该接口的setBeanFactory(BeanFactory beanFactory)方法,传入该Bean的BeanFactory,这样该Bean就获得了自己所在的BeanFactory
  5. 如果Bean实现了ApplicationContextAware接口,则调用该接口的setApplicationContext(ApplicationContext applicationContext)方法,设置applicationContext
  6. 如果有Bean实现了BeanPostProcessor接口,则调用该接口的postProcessBeforeInitialzation(Object bean,String beanName)方法,将此BeanPostProcessor应用于给定的新bean实例
  7. 如果Bean实现了InitializingBean接口,则会回调该接口的afterPropertiesSet()方法
  8. 如果Bean配置了init-method方法,则会执行init-method配置的方法
  9. 如果Bean实现了BeanPostProcessor接口,则会回调该接口的postProcessAfterInitialization(Object bean,String beanName)方法
  10. 到此为止,spring中的bean已经可以使用了,这里又涉及到了bean的作用域问题,对于singleton类型的bean,Spring会将其缓存;对于prototype类型的bean,不缓存,每次都创建新的bean的实例
  11. 容器关,如果Bean实现了DisposableBean接口,则会回调该接口的destroy()方法销毁bean,
  12. 如果用户配置了定destroy-method,则调用自定义方法销毁bean

    到此为止,bean的实例化到销毁过程,就是整个bean的生命周期了。下面来看一个实际的例子:

    2.1 新建bean
package com.lyc.cn.day02;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class MyLifeCycleBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {

    // 姓名
    private String name;
    // 年龄
    private int age;

    @Override
    public void setBeanName(String name) {
        System.out.println("01-->BeanNameAware接口被调用了, 获取到的beanName:" + name);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("02-->BeanFactoryAware接口被调用了");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("03-->ApplicationContextAware接口被调用了");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("05-->InitializingBean接口被调用了");

    }

    public void myInit() {
        System.out.println("06-->myInit方法被调用了");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("09-->DisposableBean接口被调用了");
    }

    public void myDestroy() {
        System.out.println("10-->自定义destroy-method方法被调动了");
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "MyLifeCycleBean{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
}
2.2 新建MyBeanPostProcessor并实现BeanPostProcessor接口
package com.lyc.cn.day02;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("04-->调用postProcessBeforeInitialization方法, 获取到的beanName: " + beanName);
        ((MyLifeCycleBean) bean).setName("李四");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("07-->调用postProcessAfterInitialization, 获取到的beanName: " + beanName);
        ((MyLifeCycleBean) bean).setAge(30);
        return bean;
    }

}
2.3 新建day02.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--注意:这里配置的name是张三,age是25,我们会通过beanPostProcessor来修改nage和age -->
    <bean id="myLifeCycleBean" name="myLifeCycleBean1,myLifeCycleBean2" class="com.lyc.cn.day02.MyLifeCycleBean" destroy-method="myDestroy"
          init-method="myInit">
        <property name="name" value="张三"/>
        <property name="age" value="25"/>
    </bean>

    <bean id="myBeanPostProcessor" class="com.lyc.cn.day02.MyBeanPostProcessor"/>
</beans>
2.4 新建测试用例
package com.lyc.cn.day02;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyLifeCycleBeanTest {
    @Before
    public void before() {
        System.out.println("---bean生命周期开始---\n");
    }

    @After
    public void after() {
        System.out.println("\n---bean生命周期结束---");
    }

    /**
     * 生命周期测试
     */
    @Test
    public void testDefaultConstructor() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("day02.xml");
        MyLifeCycleBean myLifeCycleBean = applicationContext.getBean("myLifeCycleBean", MyLifeCycleBean.class);
        System.out.println("08-->bean可以被使用了, beanInfo: " + myLifeCycleBean.toString());
        ((ClassPathXmlApplicationContext) applicationContext).destroy();
    }
}
2.5 测试,程序输出如下
---bean生命周期开始---

01-->BeanNameAware接口被调用了, 获取到的beanName:myLifeCycleBean
02-->BeanFactoryAware接口被调用了
03-->ApplicationContextAware接口被调用了
04-->调用postProcessBeforeInitialization方法, 获取到的beanName: myLifeCycleBean
05-->InitializingBean接口被调用了
06-->myInit方法被调用了
07-->调用postProcessAfterInitialization, 获取到的beanName: myLifeCycleBean
08-->bean可以被使用了, beanInfo: MyLifeCycleBean{name='李四', age=30}
09-->DisposableBean接口被调用了
10-->自定义destroy-method方法被调动了

---bean生命周期结束---

可以看到,bean的生命周期按照我们刚才的分析一步一步的执行,并通过MyBeanPostProcessor中的方法修改了name和age属性,xml配置文件:name:张三,age:25程序输出的是name:李四,age:30。

猜你喜欢

转载自blog.csdn.net/lyc_liyanchao/article/details/82391647
今日推荐