- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Spring生命周期回调与容器扩展详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
本篇主要总结下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配置文件及测试类如下:
1
2
3
|
<
bean
id
=
"initMethodBeanService"
class
=
"name.liuxi.spring.ext.InitMethodBeanService"
init-method
=
"init"
>
<
property
name
=
"f2"
value
=
"2"
/>
</
bean
>
|
测试类如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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..."
);
}
}
|
执行结果打印如下:
1
2
3
4
5
|
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接口实现效果一致的生命周期回调方法 。
1
2
3
4
|
@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实例初始化后处理器示例 。
1
2
3
4
5
6
7
8
9
10
11
12
|
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配置如下:
1
2
3
4
5
6
7
8
9
10
11
|
<
bean
class
=
"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
>
<
property
name
=
"locations"
value
=
"classpath:com/foo/jdbc.properties"
/>
</
bean
>
<
bean
id
=
"dataSource"
destroy-method
=
"close"
class
=
"org.apache.commons.dbcp.BasicDataSource"
>
<
property
name
=
"driverClassName"
value
=
"${jdbc.driverClassName}"
/>
<
property
name
=
"url"
value
=
"${jdbc.url}"
/>
<
property
name
=
"username"
value
=
"${jdbc.username}"
/>
<
property
name
=
"password"
value
=
"${jdbc.password}"
/>
</
bean
>
|
属性配置文件jdbc.properties如下:
1
2
3
4
|
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类对属性配置文件的引用使用一个新的方式,如下:
1
|
<
context:property-override
location
=
"classpath:override.properties"
/>
|
override.properties属性配置文件的属性的命名规则和上面不同(上面例子中需要保证属性名和占位符一致),命名规则是beanName.property 。
1
2
3
4
|
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 。
1
2
3
4
5
6
7
8
9
|
public
class
UserBean {
private
String userName;
public
String getUserName() {
return
userName;
}
public
void
setUserName(String userName) {
this
.userName = userName;
}
}
|
Spring XML配置文件配置用户类,并给用户名属性userName注入值haha 。
1
2
3
4
|
<
bean
class
=
"name.liuxi.spring.ext.BeanFactoryPostProcessorService"
/>
<
bean
id
=
"user"
class
=
"name.liuxi.spring.ext.UserBean"
>
<
property
name
=
"userName"
value
=
"haha"
/>
</
bean
>
|
下面是自定义的bean factory后处理器,修改属性userName的值为heihei 。
1
2
3
4
5
6
7
8
9
10
11
12
|
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"
);
}
}
}
|
总结 。
以上就是本文关于Spring生命周期回调与容器扩展详解的全部内容,希望对大家有所帮助。如有不足之处,欢迎留言指出。感谢朋友们对本站的支持! 。
原文链接:http://blog.csdn.net/liuxigiant/article/details/54296578 。
最后此篇关于Spring生命周期回调与容器扩展详解的文章就讲到这里了,如果你想了解更多关于Spring生命周期回调与容器扩展详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
已关闭。这个问题是 off-topic 。目前不接受答案。 想要改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 已关闭10 年前。 Improve th
我正在尝试将 JSON 发送到我的服务器并作为结果检索 JSON。例如发送用户名和密码并取回 token 和其他内容。 这就是我正在为发送的 HTTP 请求所做的。我现在如何检索同一请求中的内容?
我有以下 xts 矩阵: > options(digits.secs = 6) > set.seed(1234) > xts(1:10, as.POSIXlt(1366039619, tz="EST"
我目前正在开发一个应用程序,当用户到达某个位置时,它会提醒用户。我希望这个应用程序也在后台运行并搜索解决方案。 在 AppStore 中,我发现了一款名为“Sleep Cycle”的应用程序,它可
我想创建一个基于 farbtastic color picker 的颜色选择器。我想要实现的是添加我想要链接到色轮的 RGB slider 。这是我到目前为止所拥有的。 app.controller(
RFC 5545 允许 RDATE 属性具有 PERIOD 数据类型。该数据类型的语义是什么?据我所知,这是未指定的。它会改变事件的持续时间吗?如果时区更改且没有持续时间怎么办? 最佳答案 尽管我
在 CodinGame学习平台,C# 教程中用作示例的问题之一是: The aim of this exercise is to check the presence of a number in a
我听说网上有一本英特尔书,它描述了特定汇编指令所需的 CPU 周期,但我找不到(经过努力)。谁能告诉我如何找到CPU周期? 这是一个例子,在下面的代码中,mov/lock 是 1 个 CPU 周期,x
据我所知,Java GC有次要GC(低成本)和主要GC周期(高成本)。如果对象在本地范围内,则会在 Minor GC 中清理它。如果对象的引用存储在代码中的其他位置,则它会在主 GC 中被清除。 例如
到目前为止,我有一个很好的自旋锁,可以用作 intendend: std::atomic_flag barrier = ATOMIC_FLAG_INIT; inline void lo
晚上好,我将 cycle2 与 prev 和 next 函数一起使用,但我无法将 prev 和 next 函数置于图像下方的中心。我环顾四周,我知道这会很愚蠢,但我就是看不到它。非常令人沮丧。谢谢加里
出于教育目的,我想知道在优化(在不同级别)和编译之后执行函数需要多少 CPU 周期。有没有办法分析代码或可执行文件以获得可重现的答案?我在 64 位 Windows 7 Pro 上使用 Eclipse
我想彻底测量和调整我的 C/C++ 代码,以便在 x86_64 系统上更好地使用缓存。我知道如何使用计数器(我的 Windows 机器上的 QueryPerformanceCounter)来测量时间,
我尝试将一些数据分组到每四周一次的存储桶中,并使用 pd.Grouper(key='created_at', freq='4W')。我希望这些组是这样的,如果我有从 2019-08-26 到 2019
我正在做一个关于随机数的大型学校项目,但我找不到 Math.random() 的句点。我安装了 7.0.800.15 版本,并且正在使用 Windows 10 计算机。我试过用一个简单的程序来确定周期
我正在努力解决我们生产环境中垃圾收集利用率高的问题,我想知道设置一个大的堆大小来保证老年代永远不会被填满是否会阻止触发主要的 GC 周期。 为了实现这一点,我想有一个特定的阈值标记会触发主要的 GC
我想测量在 Python 3 中执行加法运算所需的时钟周期数。 我写了一个程序来计算加法运算的平均值: from timeit import timeit def test(n): for i
我正在寻找一种方法来测量线程上的函数调用所花费的 cpu 周期。 示例伪代码: void HostFunction() { var startTick = CurrentThread.Cur
就 CPU 周期而言,malloc() 的成本是多少?(Vista/OS,最新版本的 gcc,最高优化级别,...) 基本上,我正在实现一个复杂的 DAG 结构(类似于链表)由一些 16B(不太常见)
C/C++ 中的类型转换会导致额外的 CPU 周期吗? 我的理解是,至少在某些情况下应该消耗额外的 CPU 周期。就像从浮点类型转换为整数一样,CPU 需要将浮点结构转换为整数。 float a=2.
我是一名优秀的程序员,十分优秀!