有时候我们会遇到相似bean
定义的情况: 这些bean
需要被同样的一组拦截器包裹 。如果需要这样定义的bean
数量很大,那么我们需要写大量重复度很高的xml
配置行或者配置代码来定义这些bean
,这显然是个可以优化解决的问题。为此,Spring AOP
提供了自动代理创建机制。该机制通过往容器中添加一个APC
来完成该任务。一个APC
其实是一个SmartInstantiationAwareBeanPostProcessor
,它会介入每个bean
的实例化和初始化,检测bean
的特征,如果该bean
符合某些特征,比如有拦截器需要应用到该bean
,那么该APC
就会为它自动创建一个代理对象,使用相应的拦截器包裹住该bean
。
在Spring AOP
相应的APC
实现机制中,首先,框架内置实现了三个自动代理创建器(auto proxy creator
,缩写为APC
):
实现类 | 优先级 |
---|---|
InfrastructureAdvisorAutoProxyCreator | 0 – 最低优先级 |
AspectJAwareAdvisorAutoProxyCreator | 1 |
AnnotationAwareAspectJAutoProxyCreator | 2 – 最高优先级 |
以上信息可以参考
AopConfigUtils.APC_PRIORITY_LIST
静态属性定义。
其次,Spring AOP
提供了将这些APC
注册到容器中的ImportBeanDefinitionRegistrar
,比如AspectJAutoProxyRegistrar
,AutoProxyRegistrar
等等。这些ImportBeanDefinitionRegistrar
进而被框架定义的@Enable*
注解所使用,这里可以参考:
@Enable* 注解 | 使用到的APC bean 注册器 |
---|---|
@EnableAspectJAutoProxy | 直接导入AspectJAutoProxyRegistrar |
@EnableGlobalMethodSecurity | 间接导入AutoProxyRegistrar |
@EnableReactiveMethodSecurity | 间接导入AutoProxyRegistrar |
@EnableTransactionManagement | 间接导入AutoProxyRegistrar |
@EnableCaching | 间接导入AutoProxyRegistrar |
最后,开发者,或者框架的某个部分,会引用上面所提到的@Enable*
注解,从而导致APC
注册器向容器登记相应的APC bean
。进而容器启动时,APC
机制就开始为我们提供服务解决文章开篇所提到的问题了。
另外,需要注意的是,在同一个Spring IoC
容器中,最多只会注册一个APC bean
,但实际上,容器启动过程中可能有多处在向容器注册APC bean
,所使用的实现类可能是以上三者之一。那么容器最终会使用哪个APC
实现类呢 ?这一点可以参考框架真正的APC bean
注册逻辑AopConfigUtils#registerAutoProxyCreatorIfNecessary
。简单来讲,每次APC
注册行为逻辑是这样的 :
- 检测是否存在已经注册的
APC bean
定义;- 不存在, 则执行
APC bean
定义注册逻辑; - 存在, 则
- 即将注册的
APC
类优先级较高,则会使用这次注册的APC
类代理已注册APC bean
定义中的bean class
; - 即将注册的
APC
类优先级较低,则什么都不做,直接返回;
- 即将注册的
- 不存在, 则执行