HOME> 本届世界杯> 认识Spring 中的BeanPostProcessor

认识Spring 中的BeanPostProcessor

关于BeanPostProcessor和BeanFactoryPostProcessors,将分2篇文章来写,这篇文章是对Spring 中BeanPostProcessor进行了总结 先看下大模型对这个类的介绍,随后...

关于BeanPostProcessor和BeanFactoryPostProcessors,将分2篇文章来写,这篇文章是对Spring 中BeanPostProcessor进行了总结

先看下大模型对这个类的介绍,随后再看下这两个类的示例,最后看下这两个类的实现。

这两个类从名字看都很类似,见名知意:BeanPostProcessor=Bean后置处理器,BeanFactoryPostProcessors=BeanFactory后置处理器

BeanPostProcessor代码语言:javascript复制在Spring 5.3中,BeanPostProcessor是一个强大的接口,它允许开发者在Spring容器中的bean实例化、配置和初始化前后添加自定义的逻辑处理。以下是关于BeanPostProcessor的详细解释:

1. 作用阶段

BeanPostProcessor在Spring容器完成bean的实例化、配置和其他的初始化前后工作。它提供了两个方法,一个在初始化方法之前执行,另一个在初始化方法之后执行。

2. 主要方法

postProcessBeforeInitialization(Object bean, String beanName):

在bean的初始化方法(如@PostConstruct标记的方法或实现InitializingBean接口中的afterPropertiesSet方法)被调用之前执行。

允许在bean的属性被设置之后,但在初始化之前,对bean进行额外的处理。

postProcessAfterInitialization(Object bean, String beanName):

在bean的初始化方法被调用之后执行。

允许在bean完成初始化后,对其进行修改或返回一个新的对象(尽管这通常不是推荐的做法,因为可能导致意外的行为)。

3. 返回值

这两个方法都不能返回null。如果返回null,那么在后续的操作中可能会遇到空指针异常,或者通过getBean()方法无法获取到bean的实例。

4. 使用方式

要使用BeanPostProcessor,你需要:

实现BeanPostProcessor接口。

实现postProcessBeforeInitialization和postProcessAfterInitialization方法。

将你的BeanPostProcessor实现注册为Spring容器中的一个bean,这样Spring就能够识别并应用它。

5. 排序和优先级

如果在Spring配置中定义了多个BeanPostProcessor,那么默认情况下,Spring容器会根据它们的定义顺序来依次调用。

但是,你可以通过实现Ordered接口或使用@Order、@Priority注解来指定优先级。

6. 应用场景

BeanPostProcessor常被用于AOP(面向切面编程)的自动代理创建、日志记录、安全检查、性能监控等场景。

7. 注意事项

由于BeanPostProcessor能够影响所有bean的初始化过程,因此在使用时需要特别小心,避免引入不必要的复杂性或错误。

如果在postProcessBeforeInitialization或postProcessAfterInitialization方法中修改了bean的状态,需要确保这些修改是预期的,并且不会对其他bean或整个应用程序产生负面影响。

8. 总结

BeanPostProcessor是Spring框架中一个非常强大的工具,它允许开发者在bean的生命周期中的关键阶段插入自定义逻辑。然而,由于其强大的能力,使用时需要谨慎,并确保理解其工作原理和潜在影响。现在写几个示例来看下是怎么执行的。

我这里定义A、B、C、D 、E、F类,分别如下:

A类

代码语言:javascript复制package org.springframework.example.BPP;

import org.springframework.beans.factory.config.BeanPostProcessor;

import org.springframework.stereotype.Component;

/**

* 注解方式

*/

@Component

public class A implements BeanPostProcessor {

@Override

public Object postProcessBeforeInitialization(Object bean, String beanName) {

System.out.println("A.postProcessBeforeInitialization");

return bean;

}

@Override

public Object postProcessAfterInitialization(Object bean, String beanName) {

System.out.println("A.postProcessAfterInitialization");

return bean;

}

}B类

代码语言:javascript复制package org.springframework.example.BPP;

import org.springframework.beans.factory.config.BeanPostProcessor;

import org.springframework.core.annotation.Order;

import org.springframework.stereotype.Component;

/**

* 注解方式,加了顺序

*/

@Component

@Order(0)

public class B implements BeanPostProcessor {

@Override

public Object postProcessBeforeInitialization(Object bean, String beanName) {

System.out.println("B.postProcessBeforeInitialization, order: 0");

return bean;

}

@Override

public Object postProcessAfterInitialization(Object bean, String beanName) {

System.out.println("B.postProcessAfterInitialization, order: 0");

return bean;

}

}C类

代码语言:javascript复制package org.springframework.example.BPP;

import org.springframework.beans.factory.config.BeanPostProcessor;

import org.springframework.core.Ordered;

import org.springframework.stereotype.Component;

/**

* 注解方式,实现Order

*/

@Component

public class C implements BeanPostProcessor, Ordered {

@Override

public Object postProcessBeforeInitialization(Object bean, String beanName) {

System.out.println("C.postProcessBeforeInitialization, order: 1");

return bean;

}

@Override

public Object postProcessAfterInitialization(Object bean, String beanName) {

System.out.println("C.postProcessAfterInitialization, order: 1");

return bean;

}

@Override

public int getOrder() {

return 1;

}

}D类

代码语言:javascript复制package org.springframework.example.BPP;

import org.springframework.beans.factory.config.BeanPostProcessor;

import org.springframework.core.PriorityOrdered;

import org.springframework.stereotype.Component;

/**

* 注解方式,实现PriorityOrdered

*/

@Component

public class D implements BeanPostProcessor, PriorityOrdered {

@Override

public Object postProcessBeforeInitialization(Object bean, String beanName) {

System.out.println("D.postProcessBeforeInitialization, PriorityOrdered: 2");

return bean;

}

@Override

public Object postProcessAfterInitialization(Object bean, String beanName) {

System.out.println("D.postProcessAfterInitialization, PriorityOrdered: 2");

return bean;

}

@Override

public int getOrder() {

return 2;

}

}E类

代码语言:javascript复制package org.springframework.example.BPP;

import org.springframework.beans.factory.config.BeanPostProcessor;

import org.springframework.core.PriorityOrdered;

import org.springframework.stereotype.Component;

/**

* 注解方式,实现PriorityOrdered

*/

@Component

public class E implements BeanPostProcessor, PriorityOrdered {

@Override

public Object postProcessBeforeInitialization(Object bean, String beanName) {

System.out.println("E.postProcessBeforeInitialization, PriorityOrdered: 3");

return bean;

}

@Override

public Object postProcessAfterInitialization(Object bean, String beanName) {

System.out.println("E.postProcessAfterInitialization, PriorityOrdered: 3");

return bean;

}

@Override

public int getOrder() {

return 3;

}

}F类

代码语言:javascript复制package org.springframework.example.BPP;

import org.springframework.beans.factory.config.BeanPostProcessor;

import org.springframework.core.Ordered;

import org.springframework.stereotype.Component;

/**

* 注解方式,实现Order

*/

@Component

public class F implements BeanPostProcessor, Ordered {

@Override

public Object postProcessBeforeInitialization(Object bean, String beanName) {

System.out.println("F.postProcessBeforeInitialization, order: 4");

return bean;

}

@Override

public Object postProcessAfterInitialization(Object bean, String beanName) {

System.out.println("F.postProcessAfterInitialization, order: 4");

return bean;

}

@Override

public int getOrder() {

return 4;

}

}BeanTest 测试类

代码语言:javascript复制package org.springframework.example.BPP;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class BeanTest {

public static void main(String[] args) {

AnnotationConfigApplicationContext applicationContext =

new AnnotationConfigApplicationContext("org.springframework.example.BPP");

}

}看下打印结果

代码语言:javascript复制D.postProcessBeforeInitialization, PriorityOrdered: 2

E.postProcessBeforeInitialization, PriorityOrdered: 3

D.postProcessAfterInitialization, PriorityOrdered: 2

E.postProcessAfterInitialization, PriorityOrdered: 3

D.postProcessBeforeInitialization, PriorityOrdered: 2

E.postProcessBeforeInitialization, PriorityOrdered: 3

D.postProcessAfterInitialization, PriorityOrdered: 2

E.postProcessAfterInitialization, PriorityOrdered: 3

D.postProcessBeforeInitialization, PriorityOrdered: 2

E.postProcessBeforeInitialization, PriorityOrdered: 3

C.postProcessBeforeInitialization, order: 1

F.postProcessBeforeInitialization, order: 4

D.postProcessAfterInitialization, PriorityOrdered: 2

E.postProcessAfterInitialization, PriorityOrdered: 3

C.postProcessAfterInitialization, order: 1

F.postProcessAfterInitialization, order: 4

D.postProcessBeforeInitialization, PriorityOrdered: 2

E.postProcessBeforeInitialization, PriorityOrdered: 3

C.postProcessBeforeInitialization, order: 1

F.postProcessBeforeInitialization, order: 4

D.postProcessAfterInitialization, PriorityOrdered: 2

E.postProcessAfterInitialization, PriorityOrdered: 3

C.postProcessAfterInitialization, order: 1

F.postProcessAfterInitialization, order: 4初步分析结果,后面再看原因:

1、打印的结果怎么是这样

2、AB为什么没有打印

3、PriorityOrdered 优先级高于Ordered

4、B类的@Order(0)好像没用

带着问题,来分析一下源码:

首先我们的BeanTest类里面的AnnotationConfigApplicationContext,new 的时候内部自带了refresh(),在refresh()里面找到registerBeanPostProcessors(beanFactory),最后在PostProcessorRegistrationDelegate类的registerBeanPostProcessors中打个断点,后面调试用。

先整体分析一下这段代码:

代码语言:javascript复制public static void registerBeanPostProcessors(

ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

// WARNING: Although it may appear that the body of this method can be easily

// refactored to avoid the use of multiple loops and multiple lists, the use

// of multiple lists and multiple passes over the names of processors is

// intentional. We must ensure that we honor the contracts for PriorityOrdered

// and Ordered processors. Specifically, we must NOT cause processors to be

// instantiated (via getBean() invocations) or registered in the ApplicationContext

// in the wrong order.

//

// Before submitting a pull request (PR) to change this method, please review the

// list of all declined PRs involving changes to PostProcessorRegistrationDelegate

// to ensure that your proposal does not result in a breaking change:

// https://github.com/spring-projects/spring-framework/issues?q=PostProcessorRegistrationDelegate+is%3Aclosed+label%3A%22status%3A+declined%22

//上面的注释看,作者意思是这样写很多循环都是有意的,不需要重构

//获取BeanPostProcessor的实现类的Bean名称集合

//抛开Spring自带的BeanPostProcessor,这里将会获取到我们自定义的ABCDEF6个类,Spring 自带的BeanPostProcessor,后面再说

String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

// Register BeanPostProcessorChecker that logs an info message when

// a bean is created during BeanPostProcessor instantiation, i.e. when

// a bean is not eligible for getting processed by all BeanPostProcessors.

//这里为什么要+1,我个人估计是因为BeanPostProcessorChecker本身也是一个BeanPostProcessor

//BeanPostProcessorChecker 用来检测不符合BeanPostProcessors规则的Bean

int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;

beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

// Separate between BeanPostProcessors that implement PriorityOrdered,

// Ordered, and the rest.

//分别收集PriorityOrdered、Ordered和没有实现排序的BeanPostProcessor和MergedBeanDefinitionPostProcessor类型的Bean

List priorityOrderedPostProcessors = new ArrayList<>();

List internalPostProcessors = new ArrayList<>();

List orderedPostProcessorNames = new ArrayList<>();

List nonOrderedPostProcessorNames = new ArrayList<>();

for (String ppName : postProcessorNames) {

//查询指定名称的Bean 是否实现PriorityOrdered 接口,判断的代码也挺复杂,暂且不关心

if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {

//获取BeanPostProcessor的实例

BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);

priorityOrderedPostProcessors.add(pp);

//如果是MergedBeanDefinitionPostProcessor类型,该处理器后面再说

if (pp instanceof MergedBeanDefinitionPostProcessor) {

internalPostProcessors.add(pp);

}

}

//如果实现了Ordered接口,则添加到orderedPostProcessorNames集合中

else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {

orderedPostProcessorNames.add(ppName);

}

//如果没有实现排序接口,则添加到nonOrderedPostProcessorNames集合中

else {

nonOrderedPostProcessorNames.add(ppName);

}

}

// First, register the BeanPostProcessors that implement PriorityOrdered.

//先排序priorityOrderedPostProcessors

//默认排序规则使用的OrderComparator,优先排序PriorityOrdered的实现类,顺序从小到大排序

sortPostProcessors(priorityOrderedPostProcessors, beanFactory);

//注册,就是往beanFactory中的一个List增加BeanPostProcessor

//这里面又判断了beanFactory 是否是AbstractBeanFactory,关于什么事AbstractBeanFactory,也留着后面讲

registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

// Next, register the BeanPostProcessors that implement Ordered.

//注册实现了Ordered的BeanPostProcessors

List orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());

for (String ppName : orderedPostProcessorNames) {

BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);

orderedPostProcessors.add(pp);

//同样判断了MergedBeanDefinitionPostProcessor

if (pp instanceof MergedBeanDefinitionPostProcessor) {

internalPostProcessors.add(pp);

}

}

//同理,排序

sortPostProcessors(orderedPostProcessors, beanFactory);

//同理,注册

registerBeanPostProcessors(beanFactory, orderedPostProcessors);

// Now, register all regular BeanPostProcessors.

//处理没有实现排序的BeanPostProcessor

List nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());

for (String ppName : nonOrderedPostProcessorNames) {

BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);

nonOrderedPostProcessors.add(pp);

if (pp instanceof MergedBeanDefinitionPostProcessor) {

internalPostProcessors.add(pp);

}

}

//同理,注册

registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

// Finally, re-register all internal BeanPostProcessors.

//最后,处理MergedBeanDefinitionPostProcessor

sortPostProcessors(internalPostProcessors, beanFactory);

registerBeanPostProcessors(beanFactory, internalPostProcessors);

// Re-register post-processor for detecting inner beans as ApplicationListeners,

// moving it to the end of the processor chain (for picking up proxies etc).

//添加ApplicationListenerDetector,其用来注册ApplicationListener类型的bean到上下文中,后面来测试一下

beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));

}下面来调试一下

解释第一个问题,打印结果解密,首先要知道在哪里调用postProcessBeforeInitialization和postProcessAfterInitialization。这里是在通过beanFactory.getBean获取Bean的时候,没有Bean就会创建一个Bean,此时就会调用到,跟进去在AbstractAutowireCapableBeanFactory–>initializeBean 内部进行调用,此处打个断点调式。

由于几个内置BeanPostProcessor的存在,运行时会多次进入断点,所以我们都跳过,进入applyBeanPostProcessorsBeforeInitialization,查看**getBeanPostProcessors()**的值,此时为几个内置BeanPostProcessor。

内置Bean自然没有我们的东西,跳过,后面的进入断点次数,不算内置BeanPostProcessor!!!。

第二次进入断点,此时beanName 是 e

此时的getBeanPostProcessors() 还是原来的内置BeanPostProcessor,跳过。

第三次进入断点,此时beanName是“c”

这时getBeanPostProcessors() 多了D、E,这时继续执行,将打印D、E的postProcessBeforeInitialization日志

继续往下执行到applyBeanPostProcessorsAfterInitialization,打印

到这里,Bean C已经处理完了,直接跳过,到下个断点

第四次进入断点是F

这里的getBeanPostProcessors() 还是DE,没有C,为什么?因为CF都是实现的Ordered,他们都是在一块处理,处理完后才添加到beanPostProcessors中。由前面的代码分析可知。

所以在这里还是打印的DE的日志。

第五次进入断点,beanName是a

这里开始打印DECF的日志

第六次进入断点,beanName是b

到这里所有的类都执行完了

解释一下第二个问题,AB为什么没有被打印。

从上面可知,AB 两个bean的创建在最后,后续没有其他Bean创建,因此没有执行AB 两个BeanPostProcessor的机会。要想打印,单独创建一个普通Bean,来测试一下。

G类

代码语言:javascript复制package org.springframework.example.BPP;

import org.springframework.stereotype.Component;

@Component

public class G {

}

这里发现一个问题,B类的order 是0,怎么会在最后?实际是因为B类被认为是没有实现排序的BeanPostProcessor,也就是 Order(0) 注解在这里没用!!!这也就回答了第四个问题。

解释第三个问题,PriorityOrdered 优先级高于Ordered,因为代码是先处理的PriorityOrdered 的实现

最后对于大模型对BeanPostProcessor的介绍中的第五点

代码语言:javascript复制5. 排序和优先级

如果在Spring配置中定义了多个BeanPostProcessor,那么默认情况下,Spring容器会根据它们的定义顺序来依次调用。

但是,你可以通过实现Ordered接口或使用@Order、@Priority注解来指定优先级。是错误的!!!目前只能通过实现Ordered或者PriorityOrdered接口

通过上面的实例测试@Order并没有起作用,@Priority 注解也没法在类上使用,查了一下该注解在javax.annotation-api中。


移动免流量卡怎么申请 – 中国移动免流量卡全攻略:从避坑到精通的智能选择指南 中国共产党百年伟大贡献