Skip to content

使用“自动代理 (Auto-proxy)”功能

到目前为止,我们已经讨论了通过使用 ProxyFactoryBean 或类似的工厂 Bean 来显式创建 AOP 代理。

Spring 还允许我们使用“自动代理” Bean 定义,它可以自动代理选定的 Bean 定义。这是建立在 Spring 的 Bean 后置处理器 (Bean Post Processor) 基础设施之上的,它允许在容器加载时修改任何 Bean 定义。

在这种模型中,你在 XML Bean 定义文件中设置一些特殊的 Bean 定义,以配置自动代理基础设施。这让你可以声明符合自动代理条件的候选目标。你无需使用 ProxyFactoryBean

实现这一点有两种主要方式:

  • 使用在当前上下文中引用特定 Bean 的自动代理创建器。
  • 由源码级元数据属性(属性驱动)驱动的自动代理创建(通常指注解驱动)。

自动代理创建器

本节介绍 org.springframework.aop.framework.autoproxy 包提供的自动代理创建器。

BeanNameAutoProxyCreator

BeanNameAutoProxyCreator 类是一个 BeanPostProcessor,它会自动为名称与字面值或通配符匹配的 Bean 创建 AOP 代理。以下示例演示了如何配置:

xml
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
	<property name="beanNames" value="jdk*,onlyJdk"/>
	<property name="interceptorNames">
		<list>
			<value>myInterceptor</value>
		</list>
	</property>
</bean>

ProxyFactoryBean 一样,这里使用了 interceptorNames 属性而不是拦截器列表,以便为原型(Prototype)类型的 Advisor 提供正确的行为。命名的“拦截器”可以是 Advisor 或任何通知类型。

使用 BeanNameAutoProxyCreator 的主要目的是以最少的配置量,一致地将相同的配置应用于多个对象。它是为多个对象应用声明式事务的流行选择。

在上述示例中,名称匹配的 Bean 定义(如 jdkMyBeanonlyJdk)只是带有目标类的普通 Bean 定义。AOP 代理会由 BeanNameAutoProxyCreator 自动创建。相同的通知将应用于所有匹配的 Bean。请注意,如果使用的是 Advisor(而不是上例中的拦截器),则切入点可能会以不同的方式应用于不同的 Bean。

DefaultAdvisorAutoProxyCreator

一个更通用且极其强大的自动代理创建器是 DefaultAdvisorAutoProxyCreator。它会自动地应用当前上下文中所有符合条件的 Advisor,而无需在自动代理创建器的 Bean 定义中包含特定的 Bean 名称。它提供了与 BeanNameAutoProxyCreator 相同的配置一致性和避免重复的优点。

使用此机制涉及:

  • 指定一个 DefaultAdvisorAutoProxyCreator Bean 定义。
  • 在同一上下文中指定任意数量的 Advisor。请注意,这些必须是 Advisor,而不能只是拦截器或通知。这是必要的,因为必须有一个切入点来评估每个通知对候选 Bean 定义的适用性。

DefaultAdvisorAutoProxyCreator 会自动评估每个 Advisor 中包含的切入点,以查看它应该将哪些通知应用于每个业务对象。

这意味着任意数量的 Advisor 都可以自动应用于每个业务对象。如果没有任何 Advisor 中的切入点匹配业务对象中的任何方法,则该对象不会被代理。随着新业务对象的 Bean 定义被添加,如果需要,它们将被自动代理。

自动代理的一个普遍优势是,它使调用者或依赖者不可能获得未经过通知处理(un-advised)的对象。在这个 ApplicationContext 上调用 getBean("businessObject1") 将返回一个 AOP 代理,而不是目标业务对象。

xml
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
	<property name="transactionInterceptor" ref="transactionInterceptor"/>
</bean>

<bean id="customAdvisor" class="com.mycompany.MyAdvisor"/>

<bean id="businessObject1" class="com.mycompany.BusinessObject1">
	<!-- 属性省略 -->
</bean>

<bean id="businessObject2" class="com.mycompany.BusinessObject2"/>

如果你想一致地将相同的通知应用于许多业务对象,DefaultAdvisorAutoProxyCreator 非常有用。一旦基础设施定义到位,你就可以添加新的业务对象,而无需包含特定的代理配置。你还可以轻松地添加额外的切面(例如跟踪或性能监控切面),且配置改动极小。


补充教学

1. 核心原理:BeanPostProcessor 到底做了什么?

自动代理能成功的魔法核心在于 BeanPostProcessor 接口。

  • 介入初始化:当 Spring 容器实例化一个 Bean 之后,在执行 init-method 前后,会调用后置处理器。
  • 偷梁换柱:自动代理创建器会扫描所有的 Advisor,如果发现当前 Bean 匹配某个 Advisor 的切入点,它就会在内存中调用 ProxyFactory 创建一个代理对象,并返回这个代理对象而不是原始对象。
  • 结果:容器中最终存储的是那个被掉包后的代理。

2. 为什么 DefaultAdvisorAutoProxyCreator 是“终极武器”?

  • 真正的解耦:目标 Bean 甚至根本不知道 AOP 的存在,拦截器那边也不需要知道自己要拦谁(由切入点表达式决定)。
  • 易出错点:如果你忘了把通知包装成 Advisor(即没有切入点),DefaultAdvisorAutoProxyCreator 将无法识别它。记住:Advice + Pointcut = Advisor

3. 现代 Spring Boot 的等价物

虽然文章中讨论的是 XML 配置,但在现代开发中:

  • @EnableAspectJAutoProxy:这个注解背后注册的就是 AnnotationAwareAspectJAutoProxyCreator,它是 DefaultAdvisorAutoProxyCreator 的子类。
  • 它不仅支持传统的 Advisor 接口,还支持识别标注了 @Aspect 注解的 POJO 类。

4. 常见坑点:循环依赖

在使用自动代理时,如果不小心让一个 Advisor 依赖了它自己要拦截的 Bean,或者拦截逻辑涉及到了还没初始化完的 Bean,可能会触发 Spring 的循环依赖报错。

  • 诊断方法:查看启动日志中是否有关于 “BeanPostProcessor checker” 的警告或 BeanCurrentlyInCreationException
  • 解决建议:尽量保持 Advisor 和拦截器的逻辑轻量,不依赖复杂的业务 Bean。

Based on Spring Framework.