• Spring IOC容器与 Bean 管理 第4关:根据 Bean 的生命周期修改属性值


    目录

    任务描述

    相关知识

    Bean 的生命周期

    后处理器

    编程要求

    测试说明

    参考代码 


    任务描述

    在传统的Java应用中,Bean的生命周期非常简单,使用new关键字对Bean进行实例化,该Bean就可以使用了,当Bean不再被使用后Java将自动进行垃圾回收。

    相比之下,Spring容器中bean的生命周期就比较细致。理解 Spring bean的生命周期非常重要,因为你或许要利用Spring提供的扩展点来自定义Bean的创建过程。

    本关任务:结合Bean的生命周期修改Beanname属性值。

    相关知识

    为了完成本关任务,你需要掌握 如下知识:

    • Bean生命周期的11个步骤。

    Bean 的生命周期

    下图展示了SpringBean生命周期的11个步骤:

    图 1 Bean 的生命周期图

    下面我们对其中部分步骤进行分析:

    • 第三步:BeanNameAware

    如果Bean实现了BeanNameAware接口,Spring将配置文件中 Beanid传给setBeanName()方法。

    1. public class bean implements BeanNameAware{
    2. @Override
    3. public void setBeanName(String beanName) {
    4. System.out.println("第三步:setBeanName方法");
    5. }
    6. }
    • 第四步:BeanFactoryAware

    如果Bean实现了ApplicationContextAware接口,它的setApplicationContext()方法将被调用,将应用上下文的引用传入到Bean中。

    1. public class bean implements ApplicationContextAware{
    2. @Override
    3. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    4. System.out.println("第四步:setApplicationContext方法");
    5. }
    6. }
    • 第六步:InitializingBean

    如果Bean实现了InitializingBean接口,Spring将调用它的afterPropertiesSet方法。

    1. public class bean implements InitializingBean{
    2. @Override
    3. public void afterPropertiesSet() throws Exception {
    4. System.out.println("第六步:afterPropertiesSet方法");
    5. }
    6. }
    • 第七、十一步:指定Bean的初始化和销毁方法;

    Bean自定义的初始化和销毁方法如下:

    1. public class bean{
    2. public void init(){
    3. System.out.println("第七步:init方法");
    4. }
    5. public void destory(){
    6. System.out.println("第十一步:destory方法");
    7. }
    8. }

    若要自定义的初始化、销毁方法被使用,则需要在Spring的配置文件中添加Beaninit-methoddestory-method属性:

    • 第十步:DisposableBean

    如果Bean实现DisposableBean接口,则执行destroy方法。

    1. public class bean implements DisposableBean{
    2. @Override
    3. public void destroy() throws Exception {
    4. System.out.println("第十步:DisposableBean的destory方法");
    5. }
    6. }

    注意:执行销毁的时候,必须手动调用close方法关闭工厂,并且只对scope="singleton"有效。

    后处理器

    • 第五、八步:BeanPostProcessor

    BeanPostProcessor 称为后处理器。如果存在bean实现; BeanPostProcessor 接口,则第五步执行; postProcessBeforeInitialization方法、第八步执行; postProcessAfterInitialization方法。

    Spring通过接口反射预先知道,当Spring容器创建任何Bean时,这些后处理器都会发生作用

    下面例子在任何Bean的初始化之前和之后输出方法名及该Bean 的名称。你还可以在初始化Bean的前后实现更复杂的逻辑,因为你有这两个访问内置Bean对象的后置处理程序的方法。

    1. public class afterBean implements BeanPostProcessor {
    2. /**
    3. * 对初始化之前的Bean进行处理
    4. * @param bean 即将初始化的 Bean
    5. * @param beanname Bean 的名称
    6. * @return 返回给用户的那个 Bean ,可以修改 Bean 也可以返回一个新的bean
    7. * @throws BeansException
    8. */
    9. @Override
    10. public Object postProcessBeforeInitialization(Object obj, String beanName) throws BeansException {
    11. System.out.println("第五步:postProcessBeforeInitialization方法"+beanName);
    12. return obj;
    13. }
    14. /**
    15. * 对初始化之后的Bean进行处理
    16. * @param bean 即将初始化的 Bean
    17. * @param beanname Bean 的名称
    18. * @return 返回给用户的那个 Bean ,可以修改 Bean 也可以返回一个新的bean
    19. * @throws BeansException
    20. */
    21. @Override
    22. public Object postProcessAfterInitialization(Object obj, String beanName) throws BeansException {
    23. System.out.println("第八步:postProcessAfterInitialization方法"+beanName);
    24. return obj;
    25. }
    26. }

    后处理Bean一般不由Bean本身实现,而是独立存在,因此需要注册到Spring容器中:

    编程要求

    请仔细阅读右侧代码,根据方法内的提示,在Begin - End区域内进行代码补充,结合Bean的生命周期将UserBean实例的name属性值修改为Jack,并把周期过程输出如下(图中的黑色字体为过程,红色字体为说明):


    图 2 周期过程图

    右侧代码文件共中有配置文件、MyBeanPostProcessor类、Task类、User类需要根据提示补充,后台会自动创建Task对象调用getBean()方法获取Bean输出周期过程。

    测试说明

    补充完代码后,点击测评,平台会对你编写的代码进行测试,当你的结果与预期输出一致时,即为通过。

    预期输出:

    1. 设置对象属性setUsername()
    2. 调用BeanNameAware的setBeanName()方法
    3. 初始化Bean之前的处理,此时我的名字:User{username='Tom'}
    4. 对初始化之后的Bean进行处理,将Bean的成员变量的值修改了
    5. 设置对象属性setUsername()
    6. User{username='Jake'}

    参考代码 

     applicationContext.xml

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    5. <bean id="user" class="com.educoder.step2.User">
    6. <property name="username" value="Tom"></property>
    7. </bean>
    8. <!-- 配置后处理器 -->
    9. <bean class="com.educoder.step2.MyBeanPostProcessor"></bean>
    10. </beans>

    MyBeanPostProcessor.java

    1. package com.educoder.step2;
    2. import org.springframework.beans.BeansException;
    3. import org.springframework.beans.factory.config.BeanPostProcessor;
    4. public class MyBeanPostProcessor implements BeanPostProcessor {
    5. //对初始化之后的Bean进行处理
    6. @Override
    7. public Object postProcessAfterInitialization(Object bean, String beanname) throws BeansException {
    8. /********** Begin **********/
    9. System.out.println("对初始化之后的Bean进行处理,将Bean的成员变量的值修改了");
    10. User stu = null;
    11. if("user".equals(beanname) || bean instanceof User) {
    12. stu = (User) bean;
    13. stu.setUsername("Jake");
    14. return stu;
    15. }
    16. return bean;
    17. /********** End **********/
    18. }
    19. //对初始化之前的Bean进行处理
    20. @Override
    21. public Object postProcessBeforeInitialization(Object bean, String beanname) throws BeansException {
    22. /********** Begin **********/
    23. System.out.println("初始化Bean之前的处理,此时我的名字:"+bean);
    24. return bean;
    25. /********** End **********/
    26. }
    27. }

    User.java

    1. package com.educoder.step2;
    2. import org.springframework.beans.factory.BeanNameAware;
    3. public class User implements BeanNameAware {
    4. private String username;
    5. public User() {}
    6. //注入username属性
    7. public void setUsername(String username) {
    8. /********** Begin **********/
    9. System.out.println("设置对象属性setUsername()");
    10. this.username = username;
    11. /********** End **********/
    12. }
    13. //实现BeanNameAware接口 并重写setBeanName方法
    14. @Override
    15. public void setBeanName(String name) {
    16. /********** Begin **********/
    17. System.out.println("调用BeanNameAware的setBeanName()方法" );
    18. /********** End **********/
    19. }
    20. //返回字符串:User{name='属性值'}
    21. @Override
    22. public String toString() {
    23. /********** Begin **********/
    24. return "User{" +
    25. "username='" + username + '\'' +
    26. '}';
    27. /********** End **********/
    28. }
    29. }

    Task.java

    1. package com.educoder.step2;
    2. import org.springframework.context.ApplicationContext;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. public class Task {
    5. //获取User类Bean实例
    6. public User getBean(){
    7. /********** Begin **********/
    8. ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
    9. User bean = (User) app.getBean("user");
    10. return bean;
    11. /********** End **********/
    12. }
    13. }

  • 相关阅读:
    【学习日记2023.5.23】 之 Redis入门未入坑
    怎么把旧电脑的用户配置文件迁移到新电脑
    Django拾遗与博客项目
    SpringBoot中级开发--事务配置管理(10)
    计算机操作系统-第十一天
    Redis分布式锁的正确使用姿势
    【UnityShader入门精要学习笔记】第十七章 表面着色器
    Shiro学习之SpringBoot整合(2)
    【C++ Efficiency】程序效率、80-20法则
    进来“抄作业”!示例代码、操作手册,尽在华为云Codelabs!
  • 原文地址:https://blog.csdn.net/ycq0_9/article/details/127737615