参与Bean的生命周期

Spring容器是个神奇的魔法师。瞧!我们把写好的类和配置文件放进Spring容器里,Spring容器就能变出各种各样的Bean。之后,各种各样的Bean存在Spring容器里,相互依赖,彼此合作,又构成一个繁忙的应用程序,处理着来自远方的各种请求;直到应用程序退出,Spring容器关闭,Bean才消失在历史的长河中。由此可见,存在Spring容器里的Bean有个从诞生到消亡的过程,这个过程俗称Bean的生命周期,具体如下:
01.运行Web应用程序
02.创建Spring容器
03.加载配置文件生成Bean的定义
04.创建实现了BeanFactoryPostProcessor接口的Bean,调用postProcessBeanFactory方法
05.创建实现了BeanPostProcessor接口的Bean
06.创建其它类型的Bean
07.通过属性注入依赖
08.调用Aware接口的方法
09.调用postProcessBeforeInitialization方法
10.调用afterPropertiesSet方法初始化Bean
11.调用postProcessAfterInitialization方法
12.存在Spring容器里的Bean开始支持整个应用程序的运行
13.退出Web应用程序
14.关闭Spring容器
15.调用destroy方法销毁Bean

可以看到Bean的生命周期从开始到结束总共经历十五个阶段,每个阶段都有每个阶段该做的事。现在,让我们以庖丁解牛的手法剖开各个阶段,瞧瞧里头具体是怎样的,以及怎样写些代码参与进去,做些我们想做的事。

阶段一:运行Web应用程序

这是事情的开端。在此阶段,Web容器将会加载和初始化Web应用程序,使之运行起来。

阶段二:创建Spring容器

Web容器初始化Web应用程序的时候,Web应用程序将会根据部署描述文件提供的信息创建两个Spring容器:一个是根应用上下文;一个是Servlet应用上下文。每个容器都有自己创建和管理着的Bean。Bean的生命周期是与Bean所在的容器关联的。

阶段三:加载配置文件生成Bean的定义

Web应用程序创建Spring容器的时候,Spring容器将会加载配置文件,解析配置文件,根据配置文件提供的信息生成BeanDefinition对象。BeanDefinition对象俗称Bean的定义,保存着关于如何创建Bean的信息。

阶段四:创建实现了BeanFactoryPostProcessor接口的Bean,调用postProcessBeanFactory方法

BeanFactoryPostProcessor是Spring提供的一个接口,具体如下:

Spring容器加载配置文件生成Bean的定义之后,开始根据Bean的定义提供的信息创建各种Bean。创建各种Bean之前,Spring容器会先看看哪些Bean实现了BeanFactoryPostProcessor接口,并在找到之后首先创建这种类型的Bean,直到创建完毕才会接着创建其它类型的Bean

Spring容器创建完成所有实现了BeanFactoryPostProcessor接口的Bean之后,在开始创建其它类型的Bean之前,会先调用那些实现了BeanFactoryPostProcessor接口的Bean的postProcessBeanFactory方法。我们可在BeanFactoryPostProcessor接口的实现里修改Bean的定义,改变Spring容器即将创建的Bean的样子。

比如,Spring提供的PropertySourcesPlaceholderConfigurer类就实现了BeanFactoryPostProcessor接口,具有读取属性文件,使用属性文件的值替换Bean的定义里保存着的属性占位符,从而把属性文件的值作为字面量值注入Bean里的功能。我们将在介绍属性占位符的时候详细介绍这些内容,这里暂不详述。

阶段五:创建实现了BeanPostProcessor接口的Bean

BeanPostProcessor是Spring提供的一个接口,具体如下:

Spring容器完成所有实现了BeanFactoryPostProcessor接口的Bean的postProcessBeanFactory方法的调用之后,开始检查Bean的定义,看看哪些Bean实现了BeanPostProcessor接口,并在找到之后开始创建这些Bean,直到创建完毕才会接着创建其它类型的Bean。BeanPostProcessor接口是为了参与Bean的初始化准备的。至于怎样参与,请往下继续阅读。

阶段六:创建其它类型的Bean

Spring容器创建完成所有实现了BeanPostProcessor接口的Bean之后,开始通过反射技术调用构造函数,创建既没实现BeanFactoryPostProcessor接口,也没实现BeanPostProcessor接口的其它类型的Bean

阶段七:通过属性注入依赖

Spring容器调用Bean的构造函数完成Bean的创建之后,开始通过属性注入依赖,完成Bean的装配。

阶段八:调用Aware接口的方法

Spring提供了很多继承了Aware接口的接口。如果我们的Bean实现了这些接口,Spring容器就能通过回调的方式把那些框架相关的Bean传给我们的Bean,使我们的Bean能够使用框架相关的Bean做些事情。常见的框架相关的Bean有BeanFactory,ApplicationContext,等等。

针对BeanFactory对象,Spring提供了BeanFactoryAware接口,具体如下:

可以看到BeanFactoryAware继承了Aware接口,定义了void setBeanFactory(BeanFactory beanFactory)这样一个接受BeanFactory类型的参数的方法。如果我们的Bean实现了BeanFactoryAware接口,Spring容器完成Bean的属性的注入之后,就会以Spring容器里存在着的BeanFactory对象作为参数调用setBeanFactory方法,把BeanFactory对象交给我们的Bean,使我们的Bean能用BeanFactory对象做些事情。

针对ApplicationContext对象,Spring提供了ApplicationContextAware接口,具体如下:

可以看到ApplicationContextAware继承了Aware接口,定义了void setApplicationContext( ApplicationContext applicationContext)这样一个接受ApplicationContext类型的参数的方法。如果我们的Bean实现了ApplicationContextAware接口,Spring容器完成Bean的属性的注入之后,就会以Spring容器里存在着的ApplicationContext对象作为参数调用setApplicationContext方法,把ApplicationContext对象交给我们的Bean,使我们的Bean能用ApplicationContext对象做些事情。

值得注意的是,BeanFactoryAware和ApplicationContextAware都继承了Aware接口。Aware接口具体如下:

里面空落落的,一个成员也没有。因为Aware接口主要作为父接口用于派生各种各样的Aware接口,使我们的Bean实现这些Aware接口之后,Spring容器可把Spring框架相关的对象作为参数调用这些接口定义的方法,让我们的Bean能用Spring框架相关的对象做些事情。

阶段九:调用postProcessBeforeInitialization方法

完成所有Aware接口的方法的调用之后,Spring容器开始进行Bean的初始化。开始初始化Bean之前,Spring容器会先查看一下Spring容器里存不存在实现了BeanPostProcessor接口的Bean。注意,实现了BeanPostProcessor接口的Bean是在阶段五的时候创建的。如果存在,则会调用所有实现了BeanPostProcessor接口的Bean的postProcessBeforeInitialization方法,在Bean的初始化之前做些事情。

因此,如果我们想在Bean的初始化开始之前做些事情,可以定义一些实现了BeanPostProcessor接口的类。

阶段十:调用afterPropertiesSet方法初始化Bean

afterPropertiesSet方法是InitializingBean接口定义的一个方法,具体如下:

Spring容器完成所有实现了BeanPostProcessor接口的Bean的postProcessBeforeInitialization方法的调用之后,就会开始检查我们的Bean需不需要进行初始化。如果需要,则开始进行初始化。初始化过程从先到后是这样的:
1.检查Bean是否定义了带有@PostConstruct注解的初始化方法。如果定义了,则调用带有@PostConstruct注解的方法进行初始化。
2.检查Bean是否实现了InitializingBean接口。如果实现了,则调用afterPropertiesSet方法进行初始化。
3.检查XML配置文件的

还有,除了可以通过

另外,如果采用配置类进行配置的话,则可通过@Bean注解的initMethod属性指定初始化方法。

阶段十一:调用postProcessAfterInitialization方法

Spring容器完成Bean的初始化之后,开始检查Spring容器里存不存在实现了BeanPostProcessor接口的Bean。注意,实现了BeanPostProcessor接口的Bean是在阶段五的时候创建的。如果存在,则会调用所有实现了BeanPostProcessor接口的Bean的postProcessAfterInitialization方法,在完成Bean的初始化之后做些事情。

因此,如果我们想在Bean的初始化完成之后做些事情,可以定义一些实现了BeanPostProcessor接口的类。

阶段十二:存在Spring容器里的Bean开始支持整个应用程序的运行

Spring容器完成所有Bean的创建和初始化之后,开始支持整个应用程序的运行,处理着来自远方的各种请求。

阶段十三:退出Web应用程序

Web应用程序退出运行。

阶段十四:关闭Spring容器

Web应用程序退出的时候,Spring容器将被关闭。

阶段十五:调用destroy方法销毁Bean

destroy方法是DisposableBean接口定义的一个方法,具体如下:

Spring容器关闭的时候,将会检查我们的Bean需不需要做些销毁工作。如果需要,则开始进行销毁。销毁过程从先到后是这样的:
1.检查Bean是否定义了带有@PreDestroy注解的销毁方法。如果定义了,则调用带有@PreDestroy注解的方法进行销毁。
2.检查Bean是否实现了DisposableBean接口。如果实现了,则调用destroy方法进行销毁。
3.检查XML配置文件的

还有,除了可以通过

另外,如果采用配置类进行配置的话,则可通过@Bean注解的destroyMethod属性指定销毁方法。

于是,Bean的整个生命周期我们已经理清楚了,也知道如何写些代码参与进去。需要特别提醒的是,虽然我们可以通过实现诸如BeanFactoryPostProcessor,BeanPostProcessor这样的接口达到参与Bean的生命周期的目的;可是,这样却会导致我们的Bean与Spring框架产生耦合。

Original: https://www.cnblogs.com/evanlin/p/15756593.html
Author: 林雪波
Title: 参与Bean的生命周期

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/571400/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 多线程笔记(四)

    Atomic/CountDownLatch/CyclicBarrier/Semaphore/Exchanger/Executors/Future 1. Atomic框架包 Atom…

    Java 2023年6月8日
    094
  • 串池StringTable与s.intern()方法 、 验证s.intern()方法(基于jdk1.8)(附1.6对比)

    验证s.intern()方法(基于jdk1.8)(附1.6对比) 1、在 jdk1.8中 s.intern()方法指的是尝试将字符串对象s放入串池中 :如果串池中有,则不会放入;若…

    Java 2023年6月7日
    084
  • MySQL基础

    DQL 查询完整语法 select 字段列表 from 表名列表 where 条件列表 group by 分组字段 having 分组后条件 order by 排序字段 limit…

    Java 2023年6月14日
    084
  • Python实现改进后的Bi-RRT算法实例

    Python实现改进后的Bi-RRT算法实例 1.背景说明 以下代码是参照 上海交通大学海洋工程国家重点实验室《基于改进双向RRT的无人艇局部路径规划算法研究》的算法思想实现的。 …

    Java 2023年6月8日
    096
  • 线程的生命周期

    线程的生命周期​ 线程具有生命周期,其中包含 5种状态(出生状态,就绪状态,运行状态、暂停状态、死亡状态)。 出生状态就是线程被创建时的状态:当线程对象调用 start()方法 后…

    Java 2023年6月9日
    091
  • maven基础入门

    maven翻译为”专家”,”内行”。Maven是Apache下的一个纯java开发的开源项目,它是一个项目管理工具,使用maven对…

    Java 2023年6月9日
    070
  • CAS 单点登录【2】自定义用户验证

    方案1:CAS默认的JDBC扩展方案: CAS自带了两种简单的通过JDBC方式验证用户的处理器。 这两个处理类位于cas-server-support-jdbc这个扩展工程下。 第…

    Java 2023年5月29日
    080
  • Docker 部署xxl-job 报错:xxl-rpc remoting error(connect timed out), for url : xxxxxx

    使用Docker 部署的xxl-job,当调度中心和执行器部署在不同的容器内,此时xxl-job调用执行器的服务就会报: address:http://172…

    Java 2023年6月5日
    094
  • 动力节点-王妈妈Springboot教程(一)Xml 和 JavaConfig

    1. Spring Boot 框架 视频观看地址 https://www.bilibili.com/video/BV1XQ4y1m7ex 1.1 第一章 Xml 和 JavaCon…

    Java 2023年6月7日
    0111
  • [springmvc]从前端获取参数以及显示

    6.接收请求参数以及数据回显 接收普通参数 参数名与前端传递的参数名相同时 前端表单名name=name $Title$ username: 后端收到的参数名String name…

    Java 2023年6月6日
    0111
  • Http协议&状态码

    什么是Http协议 Http协议即超文本传送协议 (HTTP-Hypertext transfer protocol) 。是一个简单的请求-响应协议,它通常运行在TCP之上。 它定…

    Java 2023年6月9日
    094
  • Java 顺序查找 二分查找

    查找 在 Java 中我们常用的查找有两种: 顺序查找 即:有一个数组/数列 {“a”, “b”, “c”, “d”} 我们从键盘中输入任意一个 与数组类型相同的值,然后循环遍历这…

    Java 2023年6月5日
    0202
  • 百钱买百鸡问题

    百钱买百鸡问题 题目:公元前5世纪末,中国古代数学家张丘建在他的《算经》中提出了著名的 “百钱买百鸡问题”:鸡翁一,值钱五,鸡母一,值钱三,鸡雏三,值钱一,…

    Java 2023年6月14日
    0139
  • java获取txt文件中以空格分割的字符串

    需求是用java程序获取txt文件中的数据并将姓名、职称、工资添加到新txt文件中,txt文件中数据的格式是固定的,如下: 添加后的格式是这样的: 这里不考虑工资是怎么算的,只说获…

    Java 2023年6月9日
    079
  • MySQL系统变量和字符集

    书名《MySQL是怎样运行的:从根儿上理解MySQL》可自行百度 以下是知识点总结 重新认识Mysql MySQL是一个C/S架构的软件。 在Windows安装后首先注册成服务,然…

    Java 2023年6月16日
    072
  • JDBC

    接口 接口:API。 规范。 定义方法签名。 接口和抽象了的意义上的区别。 抽象类是类,抽象类的目的就是让其他类来继承的。 只要继承从意义上来说就要说通 is a。 接口更趋向于功…

    Java 2023年6月7日
    0105
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球