您现在的位置是:首页 > 技术教程 正文

Bean 的生命周期总结

admin 阅读: 2024-03-25
后台-插件-广告管理-内容页头部广告(手机)

 

%20 %20 %20目录

%20 %20一、Bean生命周期的五个阶段

%20 %20Bean的初始化

%20 %20

%20 %20二、@PostConstruct%20和%20@PreDestroy%20各自的效果

%20 %20三、 实例化和初始化的区别

%20 %20四、为什么要先设置属性在进⾏初始化呢?

%20 %20

%20 %20

%20 %20 一、Bean生命周期的五个阶段%20

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

%20 %20 %20

Bean作为一个Java对象,具有一定的生命周期。它的生命周期包括以下几个阶段:

%20 %20
  1. 实例化:在Java应用程序中,Bean对象是通过new关键字或者反射机制来实例化的。在这个阶段,Bean对象被创建,并分配了内存空间。
  2. 设置属性(Bean注入和装配)
  3. 初始化:当Bean对象被创建后,需要进行初始化,包括设置属性值、执行一些初始化操作等。在Spring框架中,Bean的初始化可以通过配置文件中的init-method属性进行指定。
  4. 使用:在Bean初始化之后,它就可以被应用程序使用了。在使用过程中,Bean可能会调用其他对象的方法,从而导致其他Bean对象被实例化和初始化。
  5. 销毁:当Bean对象不再被使用时,应该将其销毁并释放占用的内存空间。在Spring框架中,Bean的销毁可以通过配置文件中的destroy-method属性进行指定。

总的来说,Bean对象的生命周期可以通过实例化、初始化、使用和销毁这几个阶段来描述。在Spring框架中,Bean的生命周期还可以通过BeanPostProcessor接口来进行扩展和定制。

%20 %20

为了便于理解 %20我们引用一个现实中的事件来形容  

%20 %20 %20

Bean%20的⽣命流程看似繁琐,但咱们可以以⽣活中的场景来理解它,⽐如我们现在需要买⼀栋房⼦,那么我们的流程是这样的:
%201.%20先买房(实例化,从⽆到有);
%202.%20装修(设置属性);
%203.%20买家电,如洗⾐机、冰箱、电视、空调等([各种]初始化);
%204.%20⼊住(使⽤%20Bean);
%205.%20卖出去(Bean%20销毁)。 

%20 %20 Bean的初始化%20
%20 %20
  1. 执行各种通知(BeanNameAware、BeanFactoryAware)等接口方法
  2. 初始化的前置方法(PostConstruct)
  3. 初始化方法
  4. 初始化的后置方法(PreDestroy)
%20

下面用代码演示整个Bean的生命周期:
我们用构造方式来展示实例化的效果 ,实例化和属性设置是 Java 级别的系统“事件”,其操作过程不可⼈⼯⼲预和修改  所以下面没有演示设置属性

  1. package com.example.bean.test;
  2. import org.springframework.beans.factory.BeanNameAware;
  3. import org.springframework.stereotype.Component;
  4. import javax.annotation.PostConstruct;
  5. import javax.annotation.PreDestroy;
  6. @Component
  7. public class BeanLifeComponent implements BeanNameAware {
  8. private String name;
  9. public BeanLifeComponent() {
  10. System.out.println("实例化方法执行拉");
  11. }
  12. public void setBeanName(String s) {
  13. System.out.println("执行 BeanName 的通知方法");
  14. }
  15. @PostConstruct
  16. public void postConstruct() {
  17. System.out.println("初始化方法执行");
  18. }
  19. public void use() {
  20. System.out.println("使用 Bean");
  21. }
  22. @PreDestroy
  23. public void preDestroy() {
  24. System.out.println("销毁方法执行");
  25. }
  26. }

因为初始化的前置方法和后置方法是为所有 Bean 服务的,而非为某一个 Bean 服务的,所以这两个方法不能写在某个具体的 Bean 中,否则(这两个方法)不会执行。 所以我们另外创建一个类来实现这两个方法

  1. package com.example.bean.test;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.beans.factory.config.BeanPostProcessor;
  4. import org.springframework.stereotype.Component;
  5. @Component
  6. public class MyBeanPostProcessor implements BeanPostProcessor {
  7. @Override
  8. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  9. if (beanName.equals("beanLifeComponent")) {
  10. System.out.println("初始化前置方法执行");
  11. }
  12. return bean;
  13. }
  14. @Override
  15. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  16. if (beanName.equals("beanLifeComponent")) {
  17. System.out.println("初始化后置方法执行");
  18. }
  19. return bean;
  20. }
  21. }

 在得到上下文对象这里  因为我们是使用springboot演示的 所以我们使用ConfigurableApplicationContext 来得到上下文对象

  1. package com.example.bean.test;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.context.ConfigurableApplicationContext;
  5. @SpringBootApplication
  6. public class DemoApplication {
  7. public static void main(String[] args) {
  8. // 得到上下文对象,并启动 Spring Boot 项目
  9. ConfigurableApplicationContext context =
  10. SpringApplication.run(DemoApplication.class, args);
  11. // 获取 Bean
  12. BeanLifeComponent component = context.getBean(BeanLifeComponent.class);
  13. // 使用 Bean
  14. component.use();
  15. // 停止 Spring Boot 项目
  16. context.close();
  17. }
  18. }

结果如下: 

二、@PostConstruct 和 @PreDestroy 各自的效果

  1. 当Bean被容器初始化之后,会调用@PostConstruct的注解方法。
  2. 当Bean在容器销毁之前,调用被@PreDestroy注解的方法

代码如下:所以,PostConstruct 注释用于在依赖关系注入完成之后需要执行的方法上,以执行任何初始化。此方法必须在将类放入服务之前调用。支持依赖关系注入的所有类都必须支持此注释。即使类没有请求注入任何资源,用PostConstruct 注释的方法也必须被调用。只有一个方法可以用此注释进行注释。

  1. @PostConstruct
  2. public void doPostConstruct(){
  3. System.out.println("执行了 新版本@PostConstruct 前置初始化方法");
  4. }
  5. @PreDestroy
  6. public void doPreDestroy(){
  7. System.out.println("执行新版本 @PreDestroy 销毁方法");
  8. }

PreDestroy 用与在依赖注入完成之前的方法前面执行,遵守准则:

  1. 该方法不得有任何参数
  2. 该方法的返回类型必须为 void;
  3. 该方法不得抛出已检查异常;
  4. 应用 PostConstruct 的方法可以是 public、protected、package private 或 private;
  5. 该方法不能是 static;该方法可以是 final;
  6. 该方法只会被执行一次

三、 实例化和初始化的区别

实例化和属性设置是 Java 级别的系统“事件”,其操作过程不可⼈⼯⼲预和修改;⽽初始化是给开发者提供的,可以在实例化之后,类加载完成之前进⾏⾃定义“事件”处理。

四、为什么要先设置属性在进⾏初始化呢?

仔细观察下面代码:

  1. @Service
  2. public class UserService {
  3. public UserService(){
  4. System.out.println("调⽤ User Service 构造⽅法");
  5. }
  6. public void sayHi(){
  7. System.out.println("User Service SayHi.");
  8. }
  9. }
  10. @Controller
  11. public class UserController {
  12. @Resource
  13. private UserService userService;
  14. @PostConstruct
  15. public void postConstruct() {
  16. userService.sayHi();
  17. System.out.println("执⾏ User Controller 构造⽅法");
  18. }
  19. }

我们可以发现很是为了避免空指针异常。

 

标签:
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

在线投稿:投稿 站长QQ:1888636

后台-插件-广告管理-内容页尾部广告(手机)
关注我们

扫一扫关注我们,了解最新精彩内容

搜索
排行榜