Spring 第四讲 Bean的后置处理器
pom.xml 准备
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath/>
</parent>
<groupId>org.laoshiren</groupId>
<artifactId>spring-bean-init</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Bean的生命周期
java
@Slf4j
@Component
public class LifeCycleBean {
public LifeCycleBean() {
log.info("构造");
}
@Autowired
public void autowire(@Value("${JAVA_HOME}") String home) {
log.info(" autowired JAVA_HOME {}", home);
}
@PostConstruct
public void init() {
log.info("初始化");
}
@PreDestroy
public void destroy() {
log.info("销毁");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
我们都知道实例化Bean以后会调用@PostConstruct
,销毁前会掉@PreDestroy
所修饰的方法。
java
@Slf4j
@Component
public class LifeCycleBeanPostProcessor
implements InstantiationAwareBeanPostProcessor,
DestructionAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if ("lifeCycleBean".equals(beanName)) {
log.info("---- 实例化之前执行,这里返回的对象会替换原本的Bean ");
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if ("lifeCycleBean".equals(beanName)) {
log.info("---- 实例化之后执行,这里返回false 会跳过依赖注入阶段 ");
}
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if ("lifeCycleBean".equals(beanName)) {
log.info("---- 依赖注入阶段 @Autowired @Value @Resource");
}
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("lifeCycleBean".equals(beanName)) {
log.info("---- 初始化之前执行,这里返回的对象会替换掉原本的Bean 如@PostConstruct @ConfigurationProperties ");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("lifeCycleBean".equals(beanName)) {
log.info("---- 初始化之后执行,这里返回的对象会替换掉原本的Bean 代理增强 ");
}
return bean;
}
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
if ("lifeCycleBean".equals(beanName)) {
log.info("---- 销毁之前执行 ");
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
shell
# 打印结果
[ main] com.laoshiren.app.App : Starting App using Java 1.8.0_181 on laoshiren with PID 20392 (D:\laoshiren\spring-bean-init\target\classes started by laoshiren in D:\laoshiren\spring-bean-init)
[ main] com.laoshiren.app.App : No active profile set, falling back to default profiles: default
[ main] c.l.a.l.LifeCycleBeanPostProcessor : ---- 实例化之前执行,这里返回的对象会替换原本的Bean
[ main] c.laoshiren.app.lifecycle.LifeCycleBean : 构造
[ main] c.l.a.l.LifeCycleBeanPostProcessor : ---- 实例化之后执行,这里返回false 会跳过依赖注入阶段
[ main] c.l.a.l.LifeCycleBeanPostProcessor : ---- 依赖注入阶段 @Autowired @Value @Resource
[ main] c.laoshiren.app.lifecycle.LifeCycleBean : autowired JAVA_HOME C:\Program Files\Java\jdk1.8.0_181
[ main] c.l.a.l.LifeCycleBeanPostProcessor : ---- 初始化之前执行,这里返回的对象会替换掉原本的Bean 如@PostConstruct @ConfigurationProperties
[ main] c.laoshiren.app.lifecycle.LifeCycleBean : 初始化
[ main] c.l.a.l.LifeCycleBeanPostProcessor : ---- 初始化之后执行,这里返回的对象会替换掉原本的Bean 代理增强
[ main] com.laoshiren.app.App : Started App in 0.727 seconds (JVM running for 1.27)
[ main] c.l.a.l.LifeCycleBeanPostProcessor : ---- 销毁之前执行
[ main] c.laoshiren.app.lifecycle.LifeCycleBean : 销毁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
Bean 后置处理器
java
public class Component2 {
}
public class Component3 {
}
@Slf4j
@Data
public class Component1 {
public Component1() {
log.info("构造");
}
private Component2 component2;
@Autowired
public void setComponent2(Component2 component2){
log.info("@Autowired 生效 ");
this.component2 = component2;
}
private Component3 component3;
@Resource
public void setComponent3(Component3 component3) {
log.info("@Resource 生效 ");
this.component3 = component3;
}
private String home;
@Autowired
public void setHome(@Value("${JAVA_HOME}") String home) {
log.info("@Value 生效 {}", home);
this.home = home;
}
@PostConstruct
public void init() {
log.info("初始化");
}
@PreDestroy
public void destroy() {
log.info("销毁");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
常见的Bean 后置处理器
GenericApplicationContext 是一个【干净】的容器, 没有添加额外的BeanFactory后置处理器 Bean后置处理器
AutowiredAnnotationBeanPostProcessor
用于解析@Autowired
@Value
java
public class MyBeanPostProcessorMain {
public static void main(String[] args) {
// GenericApplicationContext 是一个【干净】的容器, 没有添加额外的BeanFactory后置处理器 Bean后置处理器
GenericApplicationContext ctx = new GenericApplicationContext();
// 注册Bean
ctx.registerBean("component1", Component1.class);
ctx.registerBean("component2", Component2.class);
ctx.registerBean("component3", Component3.class);
// 默认的解析器不能解析@Value 值注入 所以使用其他的解析器
ctx.getDefaultListableBeanFactory()
.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
// 注册AutowiredAnnotationBeanPostProcessor
// 解析@Autowired @Value 注解
ctx.registerBean(AutowiredAnnotationBeanPostProcessor.class);
// 初始化容器
ctx.refresh();
ctx.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
shell
# 打印结果
[main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'component1'
[main] INFO com.laoshiren.app.bean.Component1 - 构造
[main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'JAVA_HOME' in PropertySource 'systemEnvironment' with value of type String
[main] INFO com.laoshiren.app.bean.Component1 - @Value 生效 C:\Program Files\Java\jdk1.8.0_181
[main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'component2'
[main] INFO com.laoshiren.app.bean.Component1 - @Autowired 生效
[main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'component3'
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
CommonAnnotationBeanPostProcessor
用于解析@Resource
,@PostConstruct
和@PreDestory
,注册Beanctx.registerBean(CommonAnnotationBeanPostProcessor.class);
shell
# 打印结果
[main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'component1'
[main] INFO com.laoshiren.app.bean.Component1 - 构造
[main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'component3'
[main] INFO com.laoshiren.app.bean.Component1 - @Resource 生效
[main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'component2'
[main] INFO com.laoshiren.app.bean.Component1 - @Autowired 生效
[main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'JAVA_HOME' in PropertySource 'systemEnvironment' with value of type String
[main] INFO com.laoshiren.app.bean.Component1 - @Value 生效 C:\Program Files\Java\jdk1.8.0_181
[main] INFO com.laoshiren.app.bean.Component1 - 初始化
[main] DEBUG org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@7dc5e7b4, started on Wed Jan 11 14:04:49 CST 2023
[main] INFO com.laoshiren.app.bean.Component1 - 销毁
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
Springboot 中的Bean后置处理器
java
@ConfigurationProperties(prefix = "java")
@Data
public class Bean4Properties {
private String home;
private String version;
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
Springboot中的后置处理器 用于解析@ConfigurationProperties
java
public class MyBeanPostProcessorMain {
public static void main(String[] args) {
GenericApplicationContext ctx = new GenericApplicationContext();
// 注册Bean
ctx.registerBean("bean4Properties", Bean4Properties.class);
// Springboot中的后置处理器 用于解析@ConfigurationProperties
ConfigurationPropertiesBindingPostProcessor.register(ctx.getDefaultListableBeanFactory());
// 初始化容器
// 执行BeanFactory 后置处理器
ctx.refresh();
ctx.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
关于执行顺序,我们都知道Spring中会对这些进行排序,排序规则来自各种PostProcessor 实现的Order 接口
java
public interface Ordered {
// -2147483648
int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
// 2147483647
int LOWEST_PRECEDENCE = Integer.MAX_VALUE;
int getOrder();
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
BeanPostProcessor | Order |
---|---|
CommonAnnotationBeanPostProcessor | Ordered.LOWEST_PRECEDENCE - 3 |
AutowiredAnnotationBeanPostProcessor | Ordered.LOWEST_PRECEDENCE - 2 |
ConfigurationPropertiesBindingPostProcessor | Ordered.HIGHEST_PRECEDENCE + 1 |
AutowiredAnnotationBeanPostProcessor
java
public class MyDebugAutowiredAnnotationBeanPostProcessor {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 因为传入的是一个对象所以,不会执行创建过程,依赖注入,初始化过程
beanFactory.registerSingleton("component2", new Component2());
beanFactory.registerSingleton("component3", new Component3());
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
AutowiredAnnotationBeanPostProcessor postProcessor = new AutowiredAnnotationBeanPostProcessor();
postProcessor.setBeanFactory(beanFactory);
Component1 component1 = new Component1();
// 依赖注入阶段调用 解析@Autowired @Value
postProcessor.postProcessProperties(null, component1,"component1");
System.out.println(component1);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
java
public class MyDebugAutowiredAnnotationBeanPostProcessor {
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 因为传入的是一个对象所以,不会执行创建过程,依赖注入,初始化过程
beanFactory.registerSingleton("component2", new Component2());
beanFactory.registerSingleton("component3", new Component3());
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
AutowiredAnnotationBeanPostProcessor postProcessor = new AutowiredAnnotationBeanPostProcessor();
postProcessor.setBeanFactory(beanFactory);
Component1 component1 = new Component1();
// 依赖注入阶段调用 解析@Autowired @Value
postProcessor.postProcessProperties(null, component1,"component1");
System.out.println(component1);
// 修饰属性查找值
Field component2 = Component1.class.getDeclaredField("component2");
DependencyDescriptor dependencyDescriptorField = new DependencyDescriptor(component2, false);
Object propertiesBean = beanFactory.doResolveDependency(dependencyDescriptorField, null, null, null);
System.out.println(propertiesBean);
// 方法查找值
Method setComponent2 = Component1.class.getDeclaredMethod("setComponent2", Component2.class);
DependencyDescriptor dependencyDescriptorMethod =
new DependencyDescriptor(new MethodParameter(setComponent2,0),false);
Object methodFindBean = beanFactory.doResolveDependency(dependencyDescriptorMethod, null, null, null);
System.out.println(methodFindBean);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32