Spring基础 -008-Bean的生命周期

106 阅读4分钟

Spring其实就是一个管理Bean对象的工厂,它负责对象的创建,销毁等

生命周期: ==对象从创建到销毁的整个过程==

这一章将解决以下问题

创建Bean对象前后会调用什么方法?

Bean对象什么时候销毁?

Bean对象销毁前后调用什么方法?

参考Spring源码位置: ==AbstractAutowireCapableBeanFactory== 类的 ==doCreateBean()==方法

8.1 知道Bean生命周期作用

生命周期本质在不同的时间点调用了某个类的某种方法

了解这些特殊的时间点 , 选择合适的时间点来写入不同的代码

image.png

三种颜色分别是对Bean生命周期的不同深度探索的步骤次数

8.2 Bean生命周期之5步

  1. 实例化Bean
  2. Bean属性赋值
  3. 初始化Bean
  4. 使用Bean
  5. 销毁Bean

image.png

package com.spring6.bean;

public class User {
    private String name;

    public User() {
        System.out.println("1.实例化Bean");
    }

    public void setName(String name) {
        this.name = name;
        System.out.println("2.Bean属性赋值");
    }

    public void initBean(){
        System.out.println("3.初始化Bean");
    }

    public void destroyBean(){
        System.out.println("5.销毁Bean");
    }

}

注意:配置文件中申明了 ==init== 和 ==destroy== 两种方法

<?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">

    <!--
    init-method属性指定初始化方法。
    destroy-method属性指定销毁方法。
    -->
    <bean id="userBean" class="com.powernode.spring6.bean.User" init-method="initBean" destroy-method="destroyBean">
        <property name="name" value="zhangsan"/>
    </bean>

</beans>
package com.spring6.test;

import com.powernode.spring6.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanLifecycleTest {
    @Test
    public void testLifecycle(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        User userBean = applicationContext.getBean("userBean", User.class);
        System.out.println("4.使用Bean");
        // 只有正常关闭spring容器才会执行销毁方法
        ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;
        context.close();
    }
}

image.png

需要注意的:

  • 第一:只有正常关闭spring容器,bean的销毁方法才会被调用。
  • 第二:ClassPathXmlApplicationContext类才有close()方法。
  • 第三:配置文件中的init-method指定初始化方法。destroy-method指定销毁方法。

8.3 Bean的生命周期之7步

在以上的5步中,第3步是初始化Bean,如果你还想在初始化前和初始化后添加代码,可以加入“Bean后处理器”。

编写一个类实现BeanPostProcessor类,并且重写before和after方法:

package com.spring6.bean;

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


public class LogBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean后处理器的before方法执行,即将开始初始化");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean后处理器的after方法执行,已完成初始化");
        return bean;
    }
}

注意,这里需要在配置文件中配置 "Bean后处理器"

<!--配置Bean后处理器。这个后处理器将作用于当前配置文件中所有的bean。-->
<bean class="com.powernode.spring6.bean.LogBeanPostProcessor"/>

==一定要注意:在spring.xml文件中配置的Bean后处理器将作用于当前配置文件中所有的Bean。==

image.png

8.4Bean生命周期之10步

image.png

上图中检查Bean是否实现了Aware的相关接口是什么意思?
Aware相关的接口包括:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware

  • 当Bean实现了BeanNameAware,Spring会将Bean的名字传递给Bean。
  • 当Bean实现了BeanClassLoaderAware,Spring会将加载该Bean的类加载器传递给Bean。
  • 当Bean实现了BeanFactoryAware,Spring会将Bean工厂对象传递给Bean。

测试以上10步,可以让User类实现5个接口,并实现所有方法:

  • BeanNameAware
  • BeanClassLoaderAware
  • BeanFactoryAware
  • InitializingBean
  • DisposableBean

测试代码如下:

package com.spring6.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;

public class User implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {
    private String name;

    public User() {
        System.out.println("1.实例化Bean");
    }

    public void setName(String name) {
        this.name = name;
        System.out.println("2.Bean属性赋值");
    }

    public void initBean(){
        System.out.println("6.初始化Bean");
    }

    public void destroyBean(){
        System.out.println("10.销毁Bean");
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("3.类加载器:" + classLoader);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("3.Bean工厂:" + beanFactory);
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("3.bean名字:" + name);
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("9.DisposableBean destroy");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("5.afterPropertiesSet执行");
    }
}

package com.spring6.bean;

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


public class LogBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("4.Bean后处理器的before方法执行,即将开始初始化");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("7.Bean后处理器的after方法执行,已完成初始化");
        return bean;
    }
}

image.png

通过测试可以看出来:

  • InitializingBean的方法早于init-method的执行。
  • DisposableBean的方法早于destroy-method的执行。

8.5 Bean的作用域不同 , 管理方式不同

Spring根据Bean的作用域不同会选择不同的管理方式:

  • 对于singleton作用域的Bean,Spring 能够精确地知道该Bean何时被创建,何时初始化完成,以及何时被销毁;(也就是完全掌握singleton的生命周期)

  • 而对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。

<?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">

    <!--
    init-method属性指定初始化方法。
    destroy-method属性指定销毁方法。
    -->
    <bean id="userBean" class="com.powernode.spring6.bean.User" init-method="initBean" destroy-method="destroyBean" scope="prototype">
        <property name="name" value="zhangsan"/>
    </bean>

    <!--配置Bean后处理器。这个后处理器将作用于当前配置文件中所有的bean。-->
    <bean class="com.powernode.spring6.bean.LogBeanPostProcessor"/>

</beans>

image.png

通过测试一目了然。只执行了前8步,第9和10都没有执行。

8.6 自己new的对象如何让Spring管理

代码实现

package com.spring6.bean;

public class User {
}

package com.spring6.test;

import com.spring6.bean.User;
import org.junit.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;


public class RegisterBeanTest {

    @Test
    public void testBeanRegister(){
        // 自己new的对象
        User user = new User();
        System.out.println(user);

        // 创建 默认可列表BeanFactory 对象
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        // 注册Bean
        factory.registerSingleton("userBean", user);
        // 从spring容器中获取bean
        User userBean = factory.getBean("userBean", User.class);
        System.out.println(userBean);
    }
}