25.5. 元数据和Spring AOP自动代理

元数据属性最有用的就是与Spring AOP联合使用。这提供了一个类似.NET的编程模型:声明式服务会自动提供给声明了元数据的属性。 这些元数据属性可以被框架支持,比如声明式事务管理,同时也能定制。

25.5.1. 基本原理

基于Spring AOP的自动代理功能,配置可能如下所示:

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

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

<bean id="txInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
  <property name="transactionManager" ref="transactionManager" />
  <property name="transactionAttributeSource">
    <bean class="org.springframework.transaction.interceptor.AttributesTransactionAttributeSource">
      <property name="attributes" ref="attributes" />
    </bean>
  </property>
</bean>

<bean id="attributes" class="org.springframework.metadata.commons.CommonsAttributes" />

这里的基本原理与AOP章节关于自动代理的讨论类似。

最重要的bean定义是自动代理的creator和advisor。注意实际的bean名称并不重要,重要的是它们的类。

org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator的bean定义会根据相应的advisor实现自动通告(自动代理)所有当前工厂的bean实例。 这个类不了解任何属性,但依赖于相应advisor的切入点,而切入点了解这些属性。

因此我们只需要一个能提供基于属性的声明式事务管理的AOP advisor。

这样同时能够添加自定义的advisor实现,它们能够被自动测试和应用。(如果有必要,你也可以使用带有与自动代理配置之外的标准属性相匹配的切入点的advisor。)

最后,属性bean是Commons Attributes中的Attributes的实现。把它替换为其它的org.springframework.metadata.Attributes接口实现,可以从另外的源获得属性。

25.5.2. 声明式事务管理

源码级属性的常见应用就是提供声明式事务管理。一旦有了前面的bean定义,你就可以定义任意多的需要声明式事务的应用对象。 只有定义了事务属性的类或者方法会被赋予事务通知。你唯一要做的就是定义需要的事务属性。

请注意你可以在类或方法级别指定事务属性。如果指定了类级别的属性,它将会被所有方法“继承”。方法级属性则会整体覆盖任意的类级别属性。

25.5.3. 缓冲

你还可以通过类级别属性提供缓冲行为。Spring能将这个行为赋予任何POJO。你只需要像下面这样指定一个被缓冲的业务对象的缓冲属性。

 /** 
 * @@org.springframework.aop.framework.autoproxy.target.PoolingAttribute(10)
 */
public class MyClass {

你将会需要常用的自动代理基础设施配置。然后你需要像下面这样指定一个缓冲的TargetSourceCreator。因为缓冲会影响目标的构造, 所以我们不能使用常规的通知。请注意如果一个类有一个缓冲属性,即使没有适合这个类的advisor,这个缓冲也会被应用。

<bean id="poolingTargetSourceCreator"
  class="org.springframework.aop.framework.autoproxy.metadata.AttributesPoolingTargetSourceCreator">
  <property name="attributes" ref="attributes" />
</bean>

相关的自动代理bean定义需要指定一组“custom target source creators”,包括Pooling target source creator。我们可以修改上面的示例来包含这个属性,如下所示:

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
  <property name="customTargetSourceCreators">
    <list>
      <ref bean="poolingTargetSourceCreator" />
    </list>
  </property>
</bean>

通常在Spring中使用元数据是一次性开销:一旦安装好了,其它业务对象就能非常方便地使用缓存。

因为一般对缓存的需要很少,所以很少有缓存很多业务对象的需要。所以这个特性并不被经常使用。

请参考Javadoc的org.springframework.aop.framework.autoproxy包以获得更详细的资料。可以通过很少的自定义代码来使用Commons Pool之外的另一个缓存实现。

25.5.4. 自定义元数据

因为潜在的自动代理基础设施的灵活性,我们甚至比.NET的元数据属性更强大。

我们能自定义属性来提供任何类型的申明式行为。要达到这些,你需要:

  • 定义你的自定义属性类。

  • 定义一个带有关注此自定义属性的切入点的Spring AOP Advisor

  • 通过普通的自动代理基础设施将这个Advisor作为bean定义加入到应用上下文中。

  • 给你的POJO加入属性.

有几个你可能需要这样做的潜在场所,比如自定义声明式安全管理,或者可能是缓存。

这是一个能在很多项目中显著降低配置开销的有效机制。但是要记住,这在底层依赖于AOP。你使用了越多的advisor,你运行时的配置复杂度就越高。

(如果你想知道哪个通知被对象使用,可以尝试创建一个org.springframework.aop.framework.Advised的引用。这样你能查看这些advisor。)