首页>>后端>>Spring->Spring 实操 : PostProcessor 流程及能做什么

Spring 实操 : PostProcessor 流程及能做什么

时间:2023-11-29 本站 点击:0

一 . 前言

BeanPostProcessor 是 Spring 的核心组件之一 , Bean 实现 BeanPostProcessor 可以实现很多复杂的功能

二 . PostProcessor 的结构

2.1 接口方法

该接口中主要提供了2种 , 其中提供了前置调用和后置调用 . 还可以看到 , 这里通过 default 修饰 , 所以并不是强制重写的

publicinterfaceBeanPostProcessor{defaultObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)throwsBeansException{returnbean;}defaultObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException{returnbean;}}

2.2 常见实现类

这里可以看到 , AOP , 定时 , 配置等都实现了相关的集成

三 . Spring 源码深入分析

3.1 使用案例

这一部分来看一下 Spring 内部是如何使用 PostProcessor 特性的 , 这一部分以 ScheduledAnnotationBeanPostProcessor 为例.

@OverridepublicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName){//可以看到,前置处理并没有太多处理,直接返回returnbean;}@OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName){if(beaninstanceofAopInfrastructureBean||beaninstanceofTaskScheduler||beaninstanceofScheduledExecutorService){//IgnoreAOPinfrastructuresuchasscopedproxies.returnbean;}//Step1:开始特殊处理Class<?>targetClass=AopProxyUtils.ultimateTargetClass(bean);if(!this.nonAnnotatedClasses.contains(targetClass)&&AnnotationUtils.isCandidateClass(targetClass,Arrays.asList(Scheduled.class,Schedules.class))){//Step2:获取Method对应Scheduled的集合Map<Method,Set<Scheduled>>annotatedMethods=MethodIntrospector.selectMethods(targetClass,(MethodIntrospector.MetadataLookup<Set<Scheduled>>)method->{Set<Scheduled>scheduledAnnotations=AnnotatedElementUtils.getMergedRepeatableAnnotations(method,Scheduled.class,Schedules.class);return(!scheduledAnnotations.isEmpty()?scheduledAnnotations:null);});if(annotatedMethods.isEmpty()){this.nonAnnotatedClasses.add(targetClass);}else{//Step3:方法不为空,执行ProcessannotatedMethods.forEach((method,scheduledAnnotations)->scheduledAnnotations.forEach(scheduled->processScheduled(scheduled,method,bean)));}}returnbean;}

PS : 后面就不看了 , 主要就是通过一个 ScheduledTask 运行 Runable 对象

从具体的使用上 , 不难看出 , 他是在创建Bean的时候去做补充的操作 , 那么下面来看一下具体的处理流程

这个流程在Bean 初始化流程 中进行了全面的跟踪 , 这里更关注其中的一些细节

3.2 Before/After 调用流程

入口一 : AbstractAutowireCapableBeanFactory # initializeBean 调用

applyBeanPostProcessorsBeforeInitialization

applyBeanPostProcessorsAfterInitialization 其中流程也比较简单 , for 循环所有的 BeanPostProcessors 进行处理

3.3 BeanPostProcessors 的管理

//在AbstractBeanFactory中有一个集合用于管理BeanPostProcessorprivatefinalList<BeanPostProcessor>beanPostProcessors=newBeanPostProcessorCacheAwareList();//不论是哪种类型,都会通过以下2种方式进行调用,先删除,后添加publicvoidaddBeanPostProcessors(Collection<?extendsBeanPostProcessor>beanPostProcessors){this.beanPostProcessors.removeAll(beanPostProcessors);this.beanPostProcessors.addAll(beanPostProcessors);}publicvoidaddBeanPostProcessor(BeanPostProcessorbeanPostProcessor){this.beanPostProcessors.remove(beanPostProcessor);this.beanPostProcessors.add(beanPostProcessor);}

类型一 : 手动添加的流程

可以通过手动添加的方式 ,实现 BeanPostProcessor 的添加 , 参考对象 AbstractApplicationContext

protectedvoidprepareBeanFactory(ConfigurableListableBeanFactorybeanFactory){//.............//Configurethebeanfactorywithcontextcallbacks.beanFactory.addBeanPostProcessor(newApplicationContextAwareProcessor(this));//.............}

类型二 : Refresh 环节添加

哈哈 , 又到了这个地方 , 之前看 Refresh 代码的时候就注意到了这个地方 , 会注册相关的 BeanPostProcessors

protectedvoidregisterBeanPostProcessors(ConfigurableListableBeanFactorybeanFactory){//Step1:调用PostProcessorRegistrationDelegate进行注册PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory,this);}

源码注释非常清晰 ,这里就是简单翻译了一下

publicstaticvoidregisterBeanPostProcessors(ConfigurableListableBeanFactorybeanFactory,AbstractApplicationContextapplicationContext){//postProcessor数组列表String[]postProcessorNames=beanFactory.getBeanNamesForType(BeanPostProcessor.class,true,false);//processor计数intbeanProcessorTargetCount=beanFactory.getBeanPostProcessorCount()+1+postProcessorNames.length;//注册BeanPostProcessorChecker,当bean在BeanPostProcessor实例化期间创建时,即当bean不符合所有BeanPostProcessors处理的条件时,该checker会记录信息消息beanFactory.addBeanPostProcessor(newBeanPostProcessorChecker(beanFactory,beanProcessorTargetCount));//区别PriorityOrdered,internalPostProcessorList<BeanPostProcessor>priorityOrderedPostProcessors=newArrayList<>();List<BeanPostProcessor>internalPostProcessors=newArrayList<>();//有序化List<String>orderedPostProcessorNames=newArrayList<>();List<String>nonOrderedPostProcessorNames=newArrayList<>();for(StringppName:postProcessorNames){if(beanFactory.isTypeMatch(ppName,PriorityOrdered.class)){BeanPostProcessorpp=beanFactory.getBean(ppName,BeanPostProcessor.class);priorityOrderedPostProcessors.add(pp);//运行时用于合并bean定义的后处理器回调接口if(ppinstanceofMergedBeanDefinitionPostProcessor){internalPostProcessors.add(pp);}}//如果实现了Ordered接口,则需要有序处理elseif(beanFactory.isTypeMatch(ppName,Ordered.class)){orderedPostProcessorNames.add(ppName);}else{nonOrderedPostProcessorNames.add(ppName);}}//首先,注册实现prioritordered的BeanPostProcessorssortPostProcessors(priorityOrderedPostProcessors,beanFactory);registerBeanPostProcessors(beanFactory,priorityOrderedPostProcessors);//接下来,注册实现Ordered的BeanPostProcessorsList<BeanPostProcessor>orderedPostProcessors=newArrayList<>(orderedPostProcessorNames.size());for(StringppName:orderedPostProcessorNames){BeanPostProcessorpp=beanFactory.getBean(ppName,BeanPostProcessor.class);orderedPostProcessors.add(pp);if(ppinstanceofMergedBeanDefinitionPostProcessor){internalPostProcessors.add(pp);}}sortPostProcessors(orderedPostProcessors,beanFactory);registerBeanPostProcessors(beanFactory,orderedPostProcessors);//现在,注册所有常规的BeanPostProcessorsList<BeanPostProcessor>nonOrderedPostProcessors=newArrayList<>(nonOrderedPostProcessorNames.size());for(StringppName:nonOrderedPostProcessorNames){BeanPostProcessorpp=beanFactory.getBean(ppName,BeanPostProcessor.class);nonOrderedPostProcessors.add(pp);if(ppinstanceofMergedBeanDefinitionPostProcessor){internalPostProcessors.add(pp);}}registerBeanPostProcessors(beanFactory,nonOrderedPostProcessors);//最后,重新注册所有内部BeanPostProcessorssortPostProcessors(internalPostProcessors,beanFactory);registerBeanPostProcessors(beanFactory,internalPostProcessors);//将用于检测内部bean的后处理器重新注册为ApplicationListeners,将其移动到处理器链的末端beanFactory.addBeanPostProcessor(newApplicationListenerDetector(applicationContext));}

四 . 深入定制

4.1 添加 BeanPostProcessor

方法一 : 手动添加 PS : 当然 , 这种方式过于复杂 , 适用场景不多

@AutowiredprivateDefaultListableBeanFactorybeanFactory;@Bean(initMethod="initMethod")publicCommonServicegetCommonService(){//通过BeanFactory进行添加beanFactory.addBeanPostProcessor(newCustomizePostProcessor());returnnewCommonService();}

方法二 : 直接继承接口

上面分析的时候也看到 , 实现了接口就自动添加了

五 .问题补充

5.1 与四种常见的初始化方式有什么区别 ?

回顾一下四种初始化运行的方式 :

实现 InitializingBean 接口方法 afterPropertiesSet

实现 ApplicationRunner 接口方法 run(ApplicationArguments args)

方法标注注解 @PostConstruct

@Bean(initMethod = "initMethod") 通过注解指定

调用的区别

:------>thisis@PostConstruct<-------:------>thisisInitializingBean<-------:------>thisisin@Bean(initMethod="initMethod")<-------:------>thisispostProcessBeforeInitialization<-------:------>thisispostProcessAfterInitialization<-------:------>thisispostProcessBeforeInitialization<-------:------>thisispostProcessAfterInitialization<-------:------>thisispostProcessBeforeInitialization<-------:------>thisispostProcessAfterInitialization<-------:StartedDemoApplicationin0.822seconds(JVMrunningfor2.597):------>thisisApplicationRunner:getCommonService<-------

调用次数 : 四种方法只会调用一次 ,而 postProcessBeforeInitialization 和 postProcessAfterInitialization 会在每个Bean创建的时候调用

调用时机 : 集中在每个 Bean initializeBean 环节调用

六. 我们能用它干什么 ?

这里不讨论是否真的有场景会使用 ,只是发散思维 , 去思考如何利用他的特点去做点什么

6.1 结合设计模式

代理是 postProcess 最合适的使用之一 , AOP 即使用了他的特性进行的代理 , 我们可以模拟 AOP , 去做一个更偏向于业务的静态代理模式 .

同时也可以实现装饰器模式 , 对 Bean 的处理进行加强 .

Step 1 : 准备接口和实现类

//统一接口publicinterfaceSourceable{voidmethod();}//对应实现类(实际业务类)@ServicepublicclassSourceimplementsSourceable{@Overridepublicvoidmethod(){System.out.println("theoriginalmethod!");}}

Step 2 : 准备中间类

publicclassAopProxyImplimplementsSourceable{privateSourceablesource;publicAopProxyImpl(Sourceablesource){super();//注意,代理模式是在代理类中创建一个对象//this.source=newSource();//修饰模式是传入对应的对象this.source=source;}@Overridepublicvoidmethod(){before();source.method();atfer();}privatevoidatfer(){System.out.println("afterproxy!");}privatevoidbefore(){System.out.println("beforeproxy!");}}

Step 3 : BeanPostProcessor 进行处理

@OverridepublicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName){//可以看到,前置处理并没有太多处理,直接返回returnbean;}@OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName){if(beaninstanceofAopInfrastructureBean||beaninstanceofTaskScheduler||beaninstanceofScheduledExecutorService){//IgnoreAOPinfrastructuresuchasscopedproxies.returnbean;}//Step1:开始特殊处理Class<?>targetClass=AopProxyUtils.ultimateTargetClass(bean);if(!this.nonAnnotatedClasses.contains(targetClass)&&AnnotationUtils.isCandidateClass(targetClass,Arrays.asList(Scheduled.class,Schedules.class))){//Step2:获取Method对应Scheduled的集合Map<Method,Set<Scheduled>>annotatedMethods=MethodIntrospector.selectMethods(targetClass,(MethodIntrospector.MetadataLookup<Set<Scheduled>>)method->{Set<Scheduled>scheduledAnnotations=AnnotatedElementUtils.getMergedRepeatableAnnotations(method,Scheduled.class,Schedules.class);return(!scheduledAnnotations.isEmpty()?scheduledAnnotations:null);});if(annotatedMethods.isEmpty()){this.nonAnnotatedClasses.add(targetClass);}else{//Step3:方法不为空,执行ProcessannotatedMethods.forEach((method,scheduledAnnotations)->scheduledAnnotations.forEach(scheduled->processScheduled(scheduled,method,bean)));}}returnbean;}0

补充 :

这里如果没有 , 则一定会抛出 BeanNotOfRequiredTypeException , 因为 Spring 会去坚持类是否匹配

这里我们属于静态代理 , 其实还可以更活用的使用 cglib 动态代理

还有很多种整合设计模式的方式可以灵活使用

6.2 Manager 管理指定类型对象

这种方式是在 postProcessor 中对指定的Bean 进行一个管理记录

大概的使用方式是准备一个BeanManager , 然后在 postProcessor 中进行管理

@OverridepublicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName){//可以看到,前置处理并没有太多处理,直接返回returnbean;}@OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName){if(beaninstanceofAopInfrastructureBean||beaninstanceofTaskScheduler||beaninstanceofScheduledExecutorService){//IgnoreAOPinfrastructuresuchasscopedproxies.returnbean;}//Step1:开始特殊处理Class<?>targetClass=AopProxyUtils.ultimateTargetClass(bean);if(!this.nonAnnotatedClasses.contains(targetClass)&&AnnotationUtils.isCandidateClass(targetClass,Arrays.asList(Scheduled.class,Schedules.class))){//Step2:获取Method对应Scheduled的集合Map<Method,Set<Scheduled>>annotatedMethods=MethodIntrospector.selectMethods(targetClass,(MethodIntrospector.MetadataLookup<Set<Scheduled>>)method->{Set<Scheduled>scheduledAnnotations=AnnotatedElementUtils.getMergedRepeatableAnnotations(method,Scheduled.class,Schedules.class);return(!scheduledAnnotations.isEmpty()?scheduledAnnotations:null);});if(annotatedMethods.isEmpty()){this.nonAnnotatedClasses.add(targetClass);}else{//Step3:方法不为空,执行ProcessannotatedMethods.forEach((method,scheduledAnnotations)->scheduledAnnotations.forEach(scheduled->processScheduled(scheduled,method,bean)));}}returnbean;}1

补充 :

这是最简单的使用方式 , 相对更复杂的还可以整合注解 , 整合接口或者父类 , 或者仅记录class信息等方式 ,达到自己的业务效果

6.3 注入特殊属性

从图片中我们可以看到 , BeanPostProcessor 是在 PopulateBean 环节之后进行处理的 , 那么我们可以通过这个环节 , 对 Bean 中的属性进行修饰 , 常见的使用想法包括 :

为特定属性设置动态代理

从 Remote 端获取属性 , 并且设置

这个就比较好理解了 , 实际上这个时候包括RestTemplate 都已经加载完成 , JDBC 也可以使用 , 在这个时候完全可以从远端获取配置信息

@OverridepublicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName){//可以看到,前置处理并没有太多处理,直接返回returnbean;}@OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName){if(beaninstanceofAopInfrastructureBean||beaninstanceofTaskScheduler||beaninstanceofScheduledExecutorService){//IgnoreAOPinfrastructuresuchasscopedproxies.returnbean;}//Step1:开始特殊处理Class<?>targetClass=AopProxyUtils.ultimateTargetClass(bean);if(!this.nonAnnotatedClasses.contains(targetClass)&&AnnotationUtils.isCandidateClass(targetClass,Arrays.asList(Scheduled.class,Schedules.class))){//Step2:获取Method对应Scheduled的集合Map<Method,Set<Scheduled>>annotatedMethods=MethodIntrospector.selectMethods(targetClass,(MethodIntrospector.MetadataLookup<Set<Scheduled>>)method->{Set<Scheduled>scheduledAnnotations=AnnotatedElementUtils.getMergedRepeatableAnnotations(method,Scheduled.class,Schedules.class);return(!scheduledAnnotations.isEmpty()?scheduledAnnotations:null);});if(annotatedMethods.isEmpty()){this.nonAnnotatedClasses.add(targetClass);}else{//Step3:方法不为空,执行ProcessannotatedMethods.forEach((method,scheduledAnnotations)->scheduledAnnotations.forEach(scheduled->processScheduled(scheduled,method,bean)));}}returnbean;}2

特殊对象的刷新有多种任意的使用 , 可以根据自己的业务灵活运用

6.4 其他思路

这里只是抛砖引玉 , 欢迎大佬们提出自己的想法

重构属性

定制化过程中对类进行覆盖

总结

注意点 :

applyBeanPostProcessorsBeforeInitialization 主要在 initializeBean 环节调用

applyBeanPostProcessorsAfterInitialization 除了initializeBean外还在多个环节被调用 , 包括 getSingletonFactoryBeanForTypeCheck 等等几个 Factory 去实例化的过程中

避免循环 , ManagerPostProcessor 不会处理自己

BeanPostProcessor 在每个 bean 创建时都会调用 , 过多会影响启动效率

BeanPostProcessor 主要在populateBean 之后 , 注意前后顺序


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/Spring/341.html