0

0

Spring生命周期和容器扩展使用详解

php中世界最好的语言

php中世界最好的语言

发布时间:2018-04-13 14:45:18

|

2008人浏览过

|

来源于php中文网

原创

这次给大家带来Spring生命周期和容器扩展使用详解,Spring生命周期和容器扩展使用的注意事项有哪些,下面就是实战案例,一起来看一下。

下面主要介绍:

类级别的生命周期初始化回调方法init-method配置、InitializingBean接口和PostConstruct注解

容器级别的扩展BeanPostProcessor接口和BeanFactoryPostProcessor接口

1.类级别生命周期回调

1.1init-method

参照:Springbeanxsdinit-method

init-method是在Spring配置文件中声明bean的时候的一个配置项。init-method配置项的值为类中的一个无参方法,但可抛出异常。该方法会在Spring容器实例化对象并设置完属性值之后被调用。

init-method能实现的功能与InitializingBean接口、PostConstruct注解一致

Spring配置文件及测试类如下:


   

测试类如下:

public class InitMethodBeanService {
	private static Integer f1;
	private Integer f2;
	static {
		f1 = 1;
		System.out.println("InitMethodBeanService static block execute...");
	}
	public InitMethodBeanService(){
		System.out.println("InitMethodBeanService construct method execute...");
	}
	public void init(){
		System.out.println("InitMethodBeanService init method execute...");
	}
	public Integer getF2() {
		return f2;
	}
	public void setF2(Integer f2) {
		this.f2 = f2;
		System.out.println("InitMethodBeanService setF2 method execute...");
	}
}

执行结果打印如下:

InitMethodBeanService static block execute...
InitMethodBeanService construct method execute...
InitMethodBeanService setF2 method execute...
InitMethodBeanService init method execute...
test method execute...

1.2InitializingBean接口

参照:Spring官方文档beans-factory-lifecycle-initializingbean

InitializingBean接口中声明了一个方法afterPropertiesSet,该方法会在Spring容器实例化对象并设置完属性值之后被调用。和上面的init-method实现的功能一致,因此Spring不推荐使用InitializingBean接口。

例子比较简单,不列出来了

1.3PostConstruct注解

翻译:Spring官方文档beans-postconstruct-and-predestroy-annotations

@PostConstruct注解是和init-method、InitializingBean接口实现效果一致的生命周期回调方法

@PostConstruct
public void postConstruct(){
  System.out.println("PostConstructService postConstruct method execute...");
}

总结下上面三个生命周期回调方法init-method、InitializingBean接口、@PostConstruct注解

1.都是针对单个类的实例化后处理

2.执行时间都是在类实例化完成,且成员变量完成注入之后调用的

3.对于init-method,还可以在Spring配置文件的beans元素下配置默认初始化方法,配置项为default-init-method

4.若以上三种方式配置的初始化方法都不一样,则执行顺序为:@PostConstruct注解方法–>InitializingBean的afterPropertiesSet–>init-method方法;若三种方式配置的方法一样,则方法只执行一次(参照:Spring官方文档beans-factory-lifecycle-combined-effect)

5.有初始化回调方法,对应的也有销毁的回调方法。@PostConstruct注解方法–>InitializingBean的afterPropertiesSet–>init-method方法分别对应@PreDestroy注解方法–>DisposableBean的destroy–>destroy-method方法

2.容器级别扩展

翻译:Spring官方文档3.8ContainerExtensionPoints

通常情况下,开发人员无需自定义实现一个ApplicationContext的子类去扩展SpringIOC容器,SpringIOC容器通过对外暴露的一些接口,可实现对SpringIOC容器的扩展。

2.1BeanPostProcessor接口

2.1.1bean实例初始化后处理器及后处理器链

BeanPostProcessor接口定义了两个容器级别的回调方法postProcessBeforeInitialization和postProcessAfterInitialization,用于在初始化实例后的一些逻辑处理,会针对容器中的所有实例进行处理。实现了BeanPostProcessor接口的类,称之为bean实例初始化后处理器。

若在SpringIOC容器中集成了多个实例初始化后处理器,这些后处理器构成的集合称之为bean实例初始化后处理器链。

postProcessBeforeInitialization方法在类实例化且成员变量注入完成之后执行,初始化方法(例如InitializingBean的afterPropertiesSet方法)之前执行

postProcessAfterInitialization方法在类实例化且成员变量注入完成之后执行,初始化方法(例如InitializingBean的afterPropertiesSet方法)之后执行

总结:

1.实例初始化后处理器多用于对实例的一些代理操作。Spring中一些使用到AOP的特性也是通过后处理器的方式实现的。

2.实例初始化后处理器链是多个后处理器,就会有执行顺序的问题,可以通过实现Ordered接口,指定后处理的执行顺序,Ordered接口声明了getOrder方法,方法返回值越小,后处理的优先级越高,越早执行。

3.在通过实现BeanPostProcessor接口自定义实例初始化后处理器的时候,建议也实现Ordered接口,指定优先级。

4.这些后处理器的作用域是当前的SpringIOC容器,即后处理器被声明的SpringIOC容器。对于有层次结构的SpringIOC容器,实例初始化后处理器链不会作用于其他容器所初始化的实例上,即使两个容器在同一层次结构上。

5.实例初始化后处理器的实现类只需要和普通的被Spring管理的bean一样声明,SpringIOC容器就会自动检测到,并添加到实例初始化后处理器链中。

6.相对于自动检测,我们也可以调用ConfigurableBeanFactory的addBeanPostProcessor方法,以编程的方式将一个实例初始化后处理器添加到实例初始化后处理器链中。这在需要判定添加条件的场景下比较实用。这种编程式的方式会忽略到实现的Ordered接口所指定的顺序,而会作用于所有的被自动检测的实例初始化后处理器之前。

2.1.2bean实例初始化后处理器与AOP

BeanPostProcessor是一个特殊的接口,实现这个接口的类会被作为Spring管理的bean的实例的后处理器。因此,在Spring应用上下文启动的一个特殊阶段,会直接初始化所有实现了BeanPostProcessor接口的实例,以及该实例所引用的类也会被实例化。然后作为后处理器应用于其他普通实例。

由于AOP的自动代理是以实例化后处理器的方式实现的,所以无论是bean实例初始化后处理器链实例还是其引用的实例,都不能被自动代理。因而,不要在这些实例上进行切面织入。(对于这些实例,会产生这样的日志消息:“类foo不能被所有的实例化后处理器链处理,即不能被自动代理”)。

注意:当实例化后处理器以autowiring或@Resource的方式引用其他bean,Spring容器在以类型匹配依赖注入的时候,可能会注入非指定的bean(例如:实例化后处理器实现类以Resource方式依赖bean,若set方法和被依赖的bean的名称一致或者被依赖bean未声明名称,则依赖注入会以类型匹配的方式注入,此时可能会注入非指定的bean)。这也会导致自动代理或其他方式的实例化后处理器处理失败。

2.1.3bean实例初始化后处理器示例

public class BeanPostProcessorService implements BeanPostProcessor {
	@Override
	  public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
		System.out.println("BeanPostProcessorService postProcessAfterInitialization method execute... ");
		return o;
	}
	@Override
	  public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
		System.out.println("BeanPostProcessorService postProcessBeforeInitialization method execute... ");
		return o;
	}
}

2.2BeanFactoryPostProcessor接口

2.2.1beanfactory后处理器

通过实现BeanFactoryPostProcessor接口,可以读取容器所管理的bean的配置元数据,在bean完成实例化之前进行更改,这些bean称之为beanfactory后处理器。

BeanFactoryPostProcessors与BeanPostProcessor接口的异同点:

相同点:

都是容器级别的后处理器

都可配置多个后处理器,并通过实现Ordered接口,指定执行顺序

都是针对接口声明的容器中所管理的bean进行处理,在有层级结构的容器中,不能处理其他容器中的bean,即使两个容器是同一层次

都是只需要在容器中和普通bean一样声明,容器会自动检测到,并注册为后处理器

会忽略延迟初始化属性配置

不同点:

BeanFactoryPostProcessors接口在bean**实例化前处理bean的配置元数据,BeanPostProcessor接口在bean实例化后处理bean的实例**

BeanFactoryPostProcessors接口也能通过BeanFactory.getBean()方法获取bean的实例,这样会引起bean的实例化。由于BeanFactoryPostProcessors后处理器是在所有bean实例化之前执行,通过BeanFactory.getBean()方法会导致提前实例化bean,从而打破容器标准的生命周期,这样可能会引起一些负面的影响(例如:提前实例化的bean会忽略bean实例化后处理器的处理)。

2.2.2Spring内置及自定义beanfactory后处理器

Spring内置了一些beanfactory后处理器(例如:PropertyPlaceholderConfigurer和PropertyOverrideConfigurer)。同时也支持实现BeanFactoryPostProcessor接口,自定义beanfactory后处理器。下面说说Spring内置的两个后处理器和自定义后处理器。

PropertyPlaceholderConfigurer

Spring为了避免主要的XML定义文件的修改而引起的风险,提供了配置分离,可以将一些可能变更的变量配置到属性配置文件中,并在XML定义文件中以占位符的方式引用。这样,修改配置只需要修改属性配置文件即可。PropertyPlaceholderConfigurer用于检测占位符,并替换占位符为配置属性值。示例如下:

PropertyPlaceholderConfigurer通过jdbc.properties属性配置文件,在运行时,将dataSource这个bean中数据库相关信息的属性占位符替换成对应的配置值。

XML配置如下:


  


  
  
  
  

属性配置文件jdbc.properties如下:

jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://production:9002
jdbc.username=sa
jdbc.password=root

PropertyPlaceholderConfigurer不仅支持属性配置文件的读取,也支持读取系统属性。通过systemPropertiesMode属性值可配置读取优先级。各种取值说明如下:

0:不读取系统属性

1:若引用的属性配置文件中未检索到对应占位符的配置,则读取系统属性。默认为1

2:先读取系统属性,再读取引用的属性配置文件。这种配置可能导致系统属性覆盖配置文件。

PropertyOverrideConfigurer

PropertyOverrideConfigurer类可以通过引用属性配置文件,直接给容器中的bean赋值。当一个bean的属性被多个PropertyOverrideConfigurer类实例赋值时,最后一个的值会覆盖前面的。

还是以上面给上面的dataSource的bean赋值为例:

PropertyOverrideConfigurer类对属性配置文件的引用使用一个新的方式,如下:

override.properties属性配置文件的属性的命名规则和上面不同(上面例子中需要保证属性名和占位符一致),命名规则是beanName.property

dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql:mydb
dataSource.username=sa
dataSource.password=root

支持复合属性的赋值,但是要保证引用被赋值属性的对象非空
例如:foo.fred.bob.sammy=123
自定义bean factory后处理器

自定义bean factory后处理器就是实现BeanFactoryPostProcessor接口,完成对Spring容器管理的bean的配置元数据进行修改。例如:修改类属性注入的值,示例如下:

定义一个用户类UserBean

public class UserBean {
	private String userName;
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
}

Spring XML配置文件配置用户类,并给用户名属性userName注入值haha



   

下面是自定义的bean factory后处理器,修改属性userName的值为heihei

public class BeanFactoryPostProcessorService implements BeanFactoryPostProcessor {
  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    System.out.println("BeanFactoryPostProcessorService postProcessBeanFactory method execut...");
    BeanDefinition bd = beanFactory.getBeanDefinition("user");
    MutablePropertyValues pv = bd.getPropertyValues();
    if(pv.contains("userName"))
    {
      pv.addPropertyValue("userName", "heihei");
    }
  }
}

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

AngularJS实现猜数字小游戏

RecoveryFox AI
RecoveryFox AI

AI驱动的数据恢复、文件恢复工具

下载

vue实现键盘效果

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
spring框架介绍
spring框架介绍

本专题整合了spring框架相关内容,想了解更多详细内容,请阅读专题下面的文章。

114

2025.08.06

Java Spring Security 与认证授权
Java Spring Security 与认证授权

本专题系统讲解 Java Spring Security 框架在认证与授权中的应用,涵盖用户身份验证、权限控制、JWT与OAuth2实现、跨站请求伪造(CSRF)防护、会话管理与安全漏洞防范。通过实际项目案例,帮助学习者掌握如何 使用 Spring Security 实现高安全性认证与授权机制,提升 Web 应用的安全性与用户数据保护。

29

2026.01.26

resource是什么文件
resource是什么文件

Resource文件是一种特殊类型的文件,它通常用于存储应用程序或操作系统中的各种资源信息。它们在应用程序开发中起着关键作用,并在跨平台开发和国际化方面提供支持。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

156

2023.12.20

pdf怎么转换成xml格式
pdf怎么转换成xml格式

将 pdf 转换为 xml 的方法:1. 使用在线转换器;2. 使用桌面软件(如 adobe acrobat、itext);3. 使用命令行工具(如 pdftoxml)。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1900

2024.04.01

xml怎么变成word
xml怎么变成word

步骤:1. 导入 xml 文件;2. 选择 xml 结构;3. 映射 xml 元素到 word 元素;4. 生成 word 文档。提示:确保 xml 文件结构良好,并预览 word 文档以验证转换是否成功。想了解更多xml的相关内容,可以阅读本专题下面的文章。

2091

2024.08.01

xml是什么格式的文件
xml是什么格式的文件

xml是一种纯文本格式的文件。xml指的是可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。想了解更多相关的内容,可阅读本专题下面的相关文章。

1064

2024.11.28

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1126

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

192

2025.10.17

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

158

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Spring中文手册
Spring中文手册

共0课时 | 0人学习

马士兵spring视频教程
马士兵spring视频教程

共25课时 | 9.1万人学习

AngularJS教程
AngularJS教程

共24课时 | 3.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号