spring bean xml 调用方法_品Spring:bean工厂后处理器的调用规则(文末附spring全系列教程资源)...

本文详细解析了Spring中bean工厂后处理器的调用规则,包括bean定义注册后处理器和bean工厂后处理器的区别与调用时机。文章介绍了Ordered接口、PriorityOrdered接口和@Order注解在确定执行顺序中的作用,并阐述了手动添加和bean定义注册两种类型的后处理器的调用顺序。此外,文章还讨论了bean定义注册过程中可能出现的递归情况,以及未实现接口的默认顺序处理。
摘要由CSDN通过智能技术生成

作者:编程新说李新杰

出自:微信公众号“编程新说李新杰”

原文:品Spring:bean工厂后处理器的调用规则


上一篇文章介绍了对@Configuration类的处理逻辑,这些逻辑都写在ConfigurationClassPostProcessor类中。

这个类不仅是一个“bean工厂后处理器”,还是一个“bean定义注册后处理器”。

这其实是两个接口,它们都是来操作bean定义。所以非常重要。

换句话说,能操作bean定义的,也只有这两个接口,你说重要不重要。

查看下类型信息,在整个Spring中确实只有这两个接口,如下图01:

0ace4f035be3718d0468a19b8c04f598.png

虽然它们都是进行和bean定义相关的操作,但目的却是明显不同的。

bean定义注册后处理器,就是用来向容器中注册bean定义的,造成的结果就是bean定义的数目变多。

如下图02:

baf4e7dbae3b7013472d83a1b66b88be.png

它的接口方法执行的时机是,所有的“常规bean定义”都已注册完毕,该方法允许添加进一步的bean定义注册到容器中。

编程新说注:这里的“常规bean定义”指的是,在容器refresh前就已经注册好的bean定义。

bean工厂后处理器,就是用来修改容器中的bean定义的,造成的结果就是bean定义的数目不变。

如下图03:

bbe74bfae657f78af263a87dd5ee13f0.png

它的接口方法执行的时机是,所有的bean定义都已经注册完毕,不可能再增多了,该方法允许去修改bean定义的一些属性。

后处理器除了可以作为bean定义注册到容器中之外,还可以自己new出实例来,手动添加到容器中(此时不注册bean定义)。

在容器的抽象类AbstractApplicationContext中,如下图0405:

ec44c2e5dcda7e729f586665844efc6d.png

d245c0fe46e98e9b37a5dbb6a79a1810.png

接下来就开始在refresh方法中调用后处理器了,如下图06:

56e1c3a6fefea82bef752cd42329c9a7.png

继续随着方法走,如下图07:

a589f94c2a615f602a12c051b1afdb9e.png

可见有一个代理类专门来负责调用后处理器方法,其中第二个参数就是我们手动添加的后处理器实例(一般情况下没有人添加,所以为空)。

在程序中,很多时候“顺序”都是一个非常重要的事情,相同的代码,执行顺序不同,可能就是不同的结果或报错。

在Spring中,对顺序的处理是有统一的方案的,就是接口或注解。

首先是Ordered接口,如下图08:

99431cc863065c53b02de74754ca5498.png

使用一个int类型的值表示顺序,很简单。

需要注意的是,优先级最高的却是负数最小值,优先级最低的却是正数最大值。即数值越小优先级越高。

然后是PriorityOrdered接口,如下图09:

dbda196910035615698cd85975758108.png

它只是继承了Ordered接口,啥也没做。从名字就能看出来该接口的优先级比Ordered接口要高。

接着是@Order注解,如下图10:

ff2be160ed5c5656220b8a2a88e71dc3.png

从Spring4.1开始,标准的Java注解@javax.annotation.Priority,可以作为临时替代使用,如下图11:

a8da8fb0e03373134c0e9b393ee5455b.png

在具体使用时,同一类组件最好保持风格统一,都使用接口,或都使用注解。

还有一种情况需要注意,就是对于既没有实现接口也没有标注解的类,会给它一个默认的顺序值。

一般情况下是0或最大值或最小值。就是处在中间位置,或优先级最低,或优先级最高。

下面开始具体调用这些后处理器,有好几个方面的顺序问题:

1)先调用手动添加的后处理器,再调用作为bean定义注册的后处理器

2)先调用bean定义注册后处理器,再调用bean工厂后处理器

3)先调用注册bean定义的接口方法,再调用修改bean定义的接口方法

4)先调用实现PriorityOrdered接口的,再调用实现Ordered接口的,最后是没有实现接口的

整个调用过程分为很多步进行:

第一步,先调用手动添加的bean定义注册后处理器的注册bean定义方法,如下图12:

e8c46d5bd70a822cb0627d0b0051a683.png

第二步,再调用容器中实现PriorityOrdered接口的bean定义注册后处理器的注册bean定义方法,如下图13:

ee49584ad0c23e966189a2280ef2fa8c.png

第三步,再调用容器中实现Ordered接口的bean定义注册后处理器的注册bean定义方法,如下图14:

9a7265b13115b04fc9bebf1f79bd7c67.png

第四步,再通过循环调用容器中剩余所有的bean定义注册后处理器的注册bean定义方法,如下图15:

f14855adec64d5869bcdbc2e4723e46f.png

编程新说注

此处为什么要通过循环一直调用呢?因为这是在注册bean定义,而且注册的bean定义可能又是一个bean定义注册后处理器。

这很好理解,就像买饮料遇到再来一瓶一样的道理。

你买了10瓶,全部打开,有8个再来一瓶,老板又给了你8瓶,再全部打开,有5个再来一瓶,老板再给你5瓶,你接着再打开。

如此反复,直到没有遇到再来一瓶为止。

截止到目前,所有注册bean定义的方法都已经调完,这意味着bean定义注册已经完毕,bean定义的数目不会再增多了。

第五步,调用所有bean定义注册后处理器的修改bean定义方法,按需对bean定义进行修改或完善,执行顺序和上面保持一致,如下图16:

2451abf8a6dffbf4eea427587cbdd708.png

截止到目前,所有的bean定义注册后处理器接口已经全部调用完毕。接下来该调用bean工厂后处理器了。

第六步,调用手动添加的bean工厂后处理器的修改bean定义方法,如下图17:

7144e431304fc8ba139f72d53325df89.png

第七步,调用容器中实现PriorityOrdered接口的bean工厂后处理器的修改bean定义方法,如下图18:

1f68f1454d79bad4e00e13241f57ee36.png

编程新说注

可以看到这里的写法和上面不太一样,上面每次都从容器中获取,是因为bean定义的数量一直在增加。

现在bean定义数量不会再变了,从容器中获取一次即可,一个循环就可以按实现的接口不同把它们分开。

第八步,调用容器中实现Ordered接口的bean工厂后处理器的修改bean定义方法,如下图19:

d68565b187cf6a89839376d894935d6e.png

第九步,调用容器中没有实现接口的bean工厂后处理器的修改bean定义方法,如下图20:

da86a557d3368503e128f8796a968739.png

因为没有实现接口,所以这一步不用排序。

截止到现在,所有的bean定义都已经修改完毕。bean定义的属性不会再有任何变化了。

总结一下

本文介绍了两个“后处理器”接口,一个用于注册bean定义,一个用于修改bean定义。

这也是Spring中仅有的两个能够操作bean定义的接口。所以它们非常重要。

然后它们的调用顺序也很重要,如先注册bean定义,才能修改bean定义。

还有对PriorityOrdered接口和Ordered接口,以及没有接口的应用。

对bean定义注册后处理器采用类似“再来一瓶”的调用方式。因为新增加的bean定义可能还是这种类型的。

对bean工厂后处理器采用普通的调用方式,因为bean定义数量不再变化。

截止到目前,所有的bean定义已经全部就绪,等待着进入下一个阶段。

(END)


spring全系列教程资源:

https://shimo.im/docs/mAZnpJeN05knO0y1​shimo.im
88f7d0a64acb3ddf7b8dc40e77ccb23a.png
Java基础、入门、精通、架构师全套资源 Java基础、入门、精通、架构师全套资源​shimo.im
88f7d0a64acb3ddf7b8dc40e77ccb23a.png

f354fe475477938b3b11e8cdebce49ef.png

35fee3dbdfc5cc8d079e2230c3d43e41.png

b9ce78982917a8375ba8c87adda9b907.png

4fa8871023fb676dc0e5ae32ea9eda0d.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值