Spring Bean的生命周期流程

前言

Java 中的公共类称之为Java Bean,而 Spring 中的 Bean 指的是将对象的生命周期,交给Spring IoC 容器来管理的对象。所以 Spring 中的 Bean 对象在使用时,无需通过 new 来创建对象,只需要通过 DI(依赖注入),从 Spring 中取出要使用的对象即可。

在Spring框架中单实例Bean的初始化和销毁过程有这样的执行顺序:

初始化顺序:@PostConstruct → InitializingBean → init-method
销毁顺序:@PreDestroy → DisposableBean → destroy-method

在初始化Bean时,@PostConstruct注解方法会首先被执行,然后是实现InitializingBean接口的afterPropertiesSet方法,最后是init-method指定的方法。

在销毁Bean时,@PreDestroy注解方法会首先被执行,然后是实现DisposableBean接口的destroy方法,最后是destroy-method指定的方法。

简单总结一下Spring Bean生命周期的流程:

  1. 实例化(通过构造器方法);
  2. 设置Bean的属性(通过setter方法);
  3. 调用Bean的初始化方法(@PostConstruct、afterPropertiesSet方法或者init-method指定的方法);
  4. Bean可以被应用程序使用;
  5. 当容器关闭时,调用Bean的销毁方法(@PreDestroy、destroy方法或者destroy-method指定的方法)。
1.Bean生命周期

Spring 中 Bean 的生命周期是指:Bean 在 Spring(IoC)中从创建到销毁的整个过程。

 Spring 中 Bean 的生命周期主要包含以下 5 部分:

  • 实例化:为 Bean 分配内存空间;
  • 设置属性:将当前类依赖的 Bean 属性,进行注入和装配;
  • 初始化:
    • 执行各种通知;
    • 执行初始化的前置方法;
    • 执行初始化方法;
    • 执行初始化的后置方法。
  • 使用 Bean:在程序中使用 Bean 对象;
  • 销毁 Bean:将 Bean 对象进行销毁操作。

需要注意的是:“实例化”和“初始化”是两个完全不同的过程,千万不要搞混;实例化只是给 Bean 分配了内存空间,而初始化则是将程序的执行权,从系统级别转换到用户级别,并开始执行用户添加的业务代码

2.代码演示

因为 Spring Boot 是基于 Spring 创建的,所以 Bean 在 Spring 或 Spring Boot 中的行为都是一致的;接下来我们使用代码的方式在 Spring Boot 中,演示一下 Bean 的生命周期。

  • 首先,我们创建一个 Bean 对象,起名为 BeanLifecycleComponent,名称可以自己指定
@Component
public class BeanLifecycleComponent implements BeanNameAware {
    public void setBeanName(String s) {
        System.out.println("执行 BeanName 的通知方法");
    }

    @PostConstruct
    public void postConstruct() {
        System.out.println("执行初始化方法");
    }

    public void use() {
        System.out.println("使用 Bean");
    }

    @PreDestroy
    public void preDestroy() {
        System.out.println("执行销毁的方法");
    }
}
  • 然后我们创建一个 MyBeanPostProcessor 类,实现初始化的前置方法和初始化的后置方法
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("beanLifecycleComponent")) {
            System.out.println("执行初始化前置方法...");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("beanLifecycleComponent")) {
            System.out.println("执行初始化后置方法...");
        }
        return bean;
    }
}

注意:初始化的前置方法和后置方法是为所有 Bean 服务的,而非为某一个 Bean 服务的,所以这两个方法不能写在某个具体的 Bean 中,要创建一个单独的类来执行,否则(这两个方法)不会执行。

  • 最后,在 Spring Boot 的启动类中获取 Bean
@SpringBootApplication
public class SpringbootDay01Application {

    public static void main(String[] args) {
        //加载上下文环境
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootDay01Application.class, args);
        // 获取Bean
        BeanLifecycleComponent component = context.getBean(BeanLifecycleComponent.class);
        // 使用Bean
        component.use();
        // 停止Spring Boot服务
        context.close();

    }

}

上面程序的执行结果输出:

问题:能不能先执行初始化再执行设置属性呢?也就是将生命周期中的步骤 2 和步骤 3 的执行顺序交换一下? 答案是否定的。

比如以下代码的执行:

@Controller
public class UserController {
    @Resource
    private UserService userService;

    @PostConstruct // 初始化方法
    public void postConstruct() {
        userService.sayHello();
    }
}

此时如果先执行步骤 2,先将 UserService 注入到当前类,再调用步骤 3 执行初始化,那么程序的执行是正常的。如果将交换步骤 2 和步骤 3 的执行顺序,那么程序执行就会报错(空指针异常),所以 Bean 的生命周期顺序必须是上面的顺序。

  • 47
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值