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

28 篇文章 11 订阅

目录

任务描述

相关知识

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属性:

  1. <bean id="bean" class="educoder.bean" init-method="init" destroy-method="destory"></bean>
  • 第十步: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容器中:

  1. <bean class="educoder.afterBean"></bean>

编程要求

请仔细阅读右侧代码,根据方法内的提示,在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

<?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.educoder.step2.User">
        <property name="username" value="Tom"></property>
    </bean>
    <!-- 配置后处理器  -->
    <bean class="com.educoder.step2.MyBeanPostProcessor"></bean>
</beans>

MyBeanPostProcessor.java

package com.educoder.step2;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
    //对初始化之后的Bean进行处理
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanname) throws BeansException {
        /**********   Begin   **********/
        System.out.println("对初始化之后的Bean进行处理,将Bean的成员变量的值修改了");
        User stu = null;
        if("user".equals(beanname) || bean instanceof User) {
            stu = (User) bean;
            stu.setUsername("Jake");
            return stu;
        }
        return  bean;
        /**********   End   **********/
    }
    //对初始化之前的Bean进行处理
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanname) throws BeansException {
        /**********   Begin   **********/
        System.out.println("初始化Bean之前的处理,此时我的名字:"+bean);
        return bean;
        /**********   End   **********/
    }
}

User.java

package com.educoder.step2;
import org.springframework.beans.factory.BeanNameAware;
public class User implements BeanNameAware {
    private String username;
    public User() {}
    //注入username属性
    public void setUsername(String username) {
        /**********   Begin   **********/
        System.out.println("设置对象属性setUsername()");
        this.username = username;
           /**********   End   **********/
    }
    //实现BeanNameAware接口  并重写setBeanName方法
    @Override
    public void setBeanName(String name) {
        /**********   Begin   **********/
        System.out.println("调用BeanNameAware的setBeanName()方法" );
           /**********   End   **********/
    }
    //返回字符串:User{name='属性值'}
    @Override
    public String toString() {
        /**********   Begin   **********/
        return "User{" +
                "username='" + username + '\'' +
                '}';
           /**********   End   **********/
    }
}

Task.java

package com.educoder.step2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Task {
    //获取User类Bean实例
    public User getBean(){
        /**********   Begin   **********/
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        User bean = (User) app.getBean("user");
        return bean;
        /**********   End   **********/
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

于建章

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值