0%

Bean的生命周期

  • Bean的生命周期
    • Bean的生命周期之5步
    • Bean的生命周期之7步
    • Bean的生命周期之10步

八、★★★Bean的生命周期

8.1 什么是Bean的生命周期

  • Bean 的生命周期就是:对象从创建开始到最终销毁的整个过程,Bean 对象从创建到销毁中经历了哪些过程。
    • 什么时候创建 Bean 对象?
    • 创建 Bean 对象的前后会调用什么方法?
    • Bean 对象什么时候销毁?
    • Bean 对象的销毁前后调用什么方法?
  • Spring 其实就是一个管理 Bean 对象的工厂,它负责对象的创建,对象的销毁等。

8.2 为什么要知道Bean的生命周期

  • 生命周期的本质是:在哪个时间节点上调用了哪个类的哪个方法
  • 我们需要充分了解在这个生命线上,都有哪些特殊的时间节点,在这些特殊节点会调用哪个类的哪个方法。
  • 我们可能需要在某个特殊的时间点上执行一段特定的代码,只有我们知道了特殊的时间节点都在哪,在该特殊节点会调用什么方法,我们才可以确定代码写到哪,这段代码就可以放到这个节点上,当生命线走到这里的时候,自然会被调用。

8.3 Bean的生命周期之5步

  • Bean 生命周期可以粗略的划分为五大步:

    • 第一步:实例化 Bean,调用无参构造方法创建对象。
    • 第二步:Bean 属性赋值,调用对象的 set 方法,进行 set 注入。
    • 第三步:初始化 Bean,调用 BeaninitBean 方法(该方法需要自己写,然后进行配置)。
    • 第四步:使用 Bean
    • 第五步:销毁 Bean,调用 BeandestroyBean 方法(该方法需要自己写,然后进行配置)。
      • 进行 Bean 的销毁,必须关闭 Spring 容器,只有关闭了 Spring 容器,Bean 才会进行销毁。

    ![](../../../../../Running Noob/计算机/Typora笔记/笔记-git仓库/Java-SSM-notebook/img/Spring/Bean的生命周期之5步.png)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.f.spring6.bean;

/**
* @author fzy
* @date 2024/1/21 12:47
*/
public class User {
private String name;

public User() {
System.out.println("第一步:无参数构造方法执行");
}

public void setName(String name) {
System.out.println("第二步:给对象的属性赋值");
this.name = name;
}

// 这个方法需要自己写,自己配,方法名随意
public void initBean() {
System.out.println("第三步:初始化Bean");
}

// 这个方法需要自己写,自己配,方法名随意
public void destroyBean() {
System.out.println("第五步:销毁Bean");
}
}
1
2
3
4
5
6
7
8
9
<?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">
<!--需要手动指定初始化方法和销毁方法-->
<bean id="user" class="com.f.spring6.bean.User" init-method="initBean" destroy-method="destroyBean">
<property name="name" value="jack"/>
</bean>
</beans>
1
2
3
4
5
6
7
8
public void testBeanLifeCycleFive() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User user = applicationContext.getBean("user", User.class);
System.out.println("第四步:使用Bean:" + user);
// 注意:必须手动关闭Spring容器,这样Spring容器才会销毁Bean
ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;
context.close();
}

8.4 Bean的生命周期之7步

  • Bean 生命周期七步,相较于 Bean 生命周期五步,在初始化 Bean 的前和后,添加了两步。

  • Bean 生命周期之 5 步中,第 3 步是初始化 Bean,在初始化前和初始化后执行的方法为 “Bean后处理器” 的 beforeafter 方法,通过 “Bean后处理器”,我们可以在初始化 Bean 的前后添加需要执行的代码。

  • 要添加 “Bean后处理器”,需要类实现 BeanPostProcessor 类,并且重写 beforeafter 方法

  • Bean 生命周期之 7 步:

    • 第一步:实例化 Bean
    • 第二步:Bean 属性赋值。
    • 第三步:执行 “Bean后处理器” 的 before 方法。
    • 第四步:初始化 Bean
    • 第五步:执行 “Bean后处理器” 的 after 方法。
    • 第六步:使用 Bean
    • 第七步:销毁 Bean

    ![](../../../../../Running Noob/计算机/Typora笔记/笔记-git仓库/Java-SSM-notebook/img/Spring/Bean的生命周期之7步.png)

  • 添加 “Bean后处理器”。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    package com.f.spring6.bean;

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

    /**
    * @author fzy
    * @date 2024/1/21 13:05
    */
    public class LogBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("执行Bean后处理器的before方法");
    // return 不要修改
    return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    // 方法有两个参数:
    // 第一个参数:刚创建的Bean对象
    // 第二个参数:Bean的名字
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("执行Bean后处理器的after方法");
    // return 不要修改
    return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
    }
  • 配置 “Bean后处理器”。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <?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">
    <!--配置Bean后处理器-->
    <!--注意:这个Bean后处理器将作用于整个配置文件中所有的Bean-->
    <bean class="com.f.spring6.bean.LogBeanPostProcessor"/>
    <!--需要手动指定初始化方法和销毁方法-->
    <bean id="user" class="com.f.spring6.bean.User" init-method="initBean" destroy-method="destroyBean">
    <property name="name" value="jack"/>
    </bean>
    </beans>
    • 注意:这个 “Bean后处理器”将作用于整个配置文件中所有的 Bean
  • 这样,如果执行的还是之前的测试方法:

    1
    2
    3
    4
    5
    6
    7
    8
    public void testBeanLifeCycleFive() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
    User user = applicationContext.getBean("user", User.class);
    System.out.println("第四步:使用Bean:" + user);
    // 注意:必须手动关闭Spring容器,这样Spring容器才会销毁Bean
    ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;
    context.close();
    }

    会发现输出结果多了两步:

    1
    2
    3
    4
    5
    6
    7
    第一步:无参数构造方法执行
    第二步:给对象的属性赋值
    执行Bean后处理器的before方法
    第三步:初始化Bean
    执行Bean后处理器的after方法
    第四步:使用Bean:com.f.spring6.bean.User@4c402120
    第五步:销毁Bean

8.5 Bean的生命周期之10步

  • Bean 生命周期十步比七步多的三步:

    • 点位1:在 “Bean后处理器” before 方法之前,在 Bean 属性赋值之后。
    • 点位2:在 “Bean后处理器” before 方法之后,在 Bean 的初始化之前。
    • 点位3:使用 Bean 之后,或者说销毁 Bean 之前。

    添加的这三个点位的特点:都是在检查你这个 Bean 是否实现了某些特定的接口,如果实现了这些接口,则 Spring 容器会调用这个接口中的方法。

    ![](../../../../../Running Noob/计算机/Typora笔记/笔记-git仓库/Java-SSM-notebook/img/Spring/Bean的生命周期之10步.png)

8.5.1 实现Aware相关接口

  • Aware 相关的接口包括:BeanNameAwareBeanClassLoaderAwareBeanFactoryAware

    • Bean 实现了 BeanNameAware,Spring 会将 Bean 的名字传递给 Bean
    • Bean 实现了 BeanClassLoaderAware,Spring 会将加载该 Bean 的类加载器传递给 Bean
    • Bean 实现了 BeanFactoryAware,Spring 会将 Bean 工厂对象传递给 Bean
  • 在 “Bean后处理器” before 方法之前,会检查 Bean 是否实现了 Aware 相关的接口,如果实现了接口则调用这些接口中的方法。

    调用这些方法的目的是为了给你传递一些数据,让你更加方便使用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    package com.f.spring6.bean;

    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanClassLoaderAware;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.BeanFactoryAware;
    import org.springframework.beans.factory.BeanNameAware;

    /**
    * @author fzy
    * @date 2024/1/21 12:47
    */
    public class User implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware {
    ...

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

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

    @Override
    public void setBeanName(String name) {
    System.out.println("Bean的名字:" + name);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    第一步:无参数构造方法执行
    第二步:给对象的属性赋值
    Bean的名字:user
    Bean的类加载器:jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b
    生产Bean的工厂:org.springframework.beans.factory.support.DefaultListableBeanFactory@77167fb7: defining beans [com.f.spring6.bean.LogBeanPostProcessor#0,user]; root of factory hierarchy
    执行Bean后处理器的before方法
    第三步:初始化Bean
    执行Bean后处理器的after方法
    第四步:使用Bean:com.f.spring6.bean.User@1165b38
    第五步:销毁Bean

8.5.2 实现InitializingBean接口

  • Bean 初始化之前,Spring 会检查 Bean 是否实现了 InitializingBean 接口,如果实现了,则调用接口中的方法。

    • InitializingBean 的方法早于 init-method 的执行。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package com.f.spring6.bean;

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

    /**
    * @author fzy
    * @date 2024/1/21 12:47
    */
    public class User implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean {
    ...

    @Override
    public void afterPropertiesSet() throws Exception {
    System.out.println("InitializingBean的afterPropertiesSet方法执行...");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    第一步:无参数构造方法执行
    第二步:给对象的属性赋值
    Bean的名字:user
    Bean的类加载器:jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b
    生产Bean的工厂:org.springframework.beans.factory.support.DefaultListableBeanFactory@77167fb7: defining beans [com.f.spring6.bean.LogBeanPostProcessor#0,user]; root of factory hierarchy
    执行Bean后处理器的before方法
    InitializingBean的afterPropertiesSet方法执行...
    第三步:初始化Bean
    执行Bean后处理器的after方法
    第四步:使用Bean:com.f.spring6.bean.User@4c12331b
    第五步:销毁Bean

8.5.3 实现DisposableBean接口

  • 在销毁 Bean 之前,检查 Bean 是否实现了 DisposableBean 接口,如果实现了,则调用接口中的方法。

    • DisposableBean 的方法 destroy() 早于 destroy-method 的执行。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package com.f.spring6.bean;

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

    /**
    * @author fzy
    * @date 2024/1/21 12:47
    */
    public class User implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {
    ...

    @Override
    public void destroy() throws Exception {
    System.out.println("DisposableBean的destroy方法执行...");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    第一步:无参数构造方法执行
    第二步:给对象的属性赋值
    Bean的名字:user
    Bean的类加载器:jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b
    生产Bean的工厂:org.springframework.beans.factory.support.DefaultListableBeanFactory@77167fb7: defining beans [com.f.spring6.bean.LogBeanPostProcessor#0,user]; root of factory hierarchy
    执行Bean后处理器的before方法
    InitializingBean的afterPropertiesSet方法执行...
    第三步:初始化Bean
    执行Bean后处理器的after方法
    第四步:使用Bean:com.f.spring6.bean.User@7586beff
    DisposableBean的destroy方法执行...
    第五步:销毁Bean

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

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

  • 对于 singleton 作用域的 Bean,Spring 能够精确地知道该 Bean 何时被创建,何时初始化完成,以及何时被销毁。

    而对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,对该 Bean 初始化完毕,等到客户端程序获取到该 Bean 之后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。

    • 因此,Spring 容器只对 singletonBean 进行完整的生命周期管理,对于 prototypeBean,Spring 只进行部分的生命周期管理。

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

  • 有些时候可能会遇到这样的需求,某个 java 对象是我们自己 new 的,然后我们希望这个对象被 Spring 容器管理。

    • 该怎么让我们自己 new 的对象让 Spring 容器管理呢?
    1
    2
    3
    4
    5
    6
    7
    8
    package com.f.spring6.bean;

    /**
    * @author fzy
    * @date 2024/1/21 13:55
    */
    public class Student {
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Test
    public void testRegisterBean() {
    // 自己new的对象
    Student student = new Student();
    System.out.println("纳入Spring管理前的Student对象:" + student);
    // 将以上自己new的对象纳入Spring容器来管理
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    factory.registerSingleton("studentBean", student);
    // 从Spring容器中获取
    Student studentBean = factory.getBean("studentBean", Student.class);
    System.out.println("纳入Spring管理后的StudentBean:" + studentBean);
    }
    1
    2
    纳入Spring管理前的Student对象:com.f.spring6.bean.Student@1cd072a9
    纳入Spring管理后的StudentBean:com.f.spring6.bean.Student@1cd072a9
    • 发现是同一个对象,说明该对象已经纳入 Spring 容器管理了。
---------------The End---------------