技术开发 频道

Spring AOP: Spring之面向方面编程

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

Spring也允许我们使用“autoproxy”的bean定义,它可以自动代理所选择的bean定义。这是建立在Spring的 “bean后处理器”机制上的,它能够在容器载入bean定义的时候修改任何bean定义。

在这个模型中,你可以在你的XML bean定义文件中建立特殊的bean定义,来配置自动代理机制。这允许你声明目标对象以使用自动代理功能: 你就可以不需要使用ProxyFactoryBean。

有两种方法来实现自动代理:

使用一个自动代理生成器,它引用当前上下文中的那些特殊bean

有一个特殊的自动代理创建的情况值得单独考虑:由源代码级元数据驱动的自动代理创建

自动代理的bean定义
org.springframework.aop.framework.autoproxy包提供了下列标准自动代理生成器。

BeanNameAutoProxyCreator
BeanNameAutoProxyCreator为名字符合某个值或统配符的bean自动创建AOP代理。

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

就和ProxyFactoryBean一样,有一个interceptorNames 属性,而不是一个拦截器列表,这个属性允许为prototype的advisor提供正确的行为。虽然名字叫 “拦截器”,但是也可以是advisor或任何通知类型。

就象一般的自动代理创建一样,使用BeanNameAutoProxyCreator的主要目的 是对多个对象使用相同的配置信息,并且减少配置的工作量。这在为多个对象使用声明式事务时是一个很流行的选择。

在上面的例子中,名字匹配的bean定义,如“jdkMyBean”和“onlyJdk”,是包含目标类的普通bean定义。 BeanNameAutoProxyCreator将自动创建AOP代理。相同的通知会被因用到所有匹配的bean。 注意,如果使用了advisor(而不是上面例子中的拦截器),切入点可能对不同的bean会不同。

DefaultAdvisorAutoProxyCreator
DefaultAdvisorAutoProxyCreator是一个更通用,更强大的自动代理生成器。它将 自动应用于当前上下文的符合条件的advisor,而不需要在自动代理advisor的bean定义中包含特定的bean名字。 它有助于配置的一致性,并避免象BeanNameAutoProxyCreator一样重复配置。

使用这个机制包括:

指定一个DefaultAdvisorAutoProxyCreator的bean定义

在相同或相关上下文中指定任何数目的Advisor。注意这些必须是Advisor, 而不仅仅是拦截器或其它通知。这是很必要的,因为必须有一个切入点来检查每个通知是否符合候选bean定义。

DefaultAdvisorAutoProxyCreator会自动计算每个advisor包含的的切入点,看看 是否有什么通知应该被引用到每个业务对象(比如例子中的“businessObject1”和“businessObject2”)。

这意味着任何数目的advisor都可以自动应用到每个业务对象。如果advisor中没有任何切入点符合业务对象的 方法,这个对象就不会被代理。因为会为新的业务对象添加bean定义,如果必要,它们会自动被代理。

一般来说,自动代理可以保证调用者或依赖无法接触未被通知的对象。在这个ApplicationContext上 调用getBean("businessObject1")返回一个AOP代理,而不是目标业务对象。

<bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"> </bean> <bean id="txAdvisor" autowire="constructor" class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"> <property name="order"><value>1</value></property> </bean> <bean id="customAdvisor" class="com.mycompany.MyAdvisor"> </bean> <bean id="businessObject1" class="com.mycompany.BusinessObject1"> <!-- Properties omitted --> </bean> <bean id="businessObject2" class="com.mycompany.BusinessObject2"> </bean>

如果你想在几个业务对象上应用相同的通知,DefaultAdvisorAutoProxyCreator 就非常有用。一旦定义恰当,你可以简单地添加业务对象而不需要包括特定的代理配置。你也可以非常容易地 删除所附加的方面--例如,跟踪或性能监控的方面--可以尽可能减少配置修改。

DefaultAdvisorAutoProxyCreator支持过滤(使用命名规则以便只计算某一些 advisor,允许在一个工厂中使用多个,被不同配置的AdvisorAutoProxyCreator)和排序。Advisor可以实现 org.springframework.core.Ordered接口以保证正确的排序,如果排序确实需要。在 上面的例子中,TransactionAttributeSourceAdvisor有一个可配置的顺序值,缺损是不排序。

AbstractAdvisorAutoProxyCreator
这是DefaultAdvisorAutoProxyCreator的父类。你可以继承它实现你自己的自动代理生成器,这种情况不太常见, 一般是advisor定义不能给DefaultAdvisorAutoProxyCreator框架的行为提供足够的定制。

使用元数据驱动的自动代理
一种特别重要的自动代理类型是由元数据驱动的。这和.NET的ServicedComponents编程框架 非常类似。它没有象EJB那样使用XML部署描述,事务管理和其它企业级业务的配置都是定义在源代码级的属性上。

在这种情况下,你可以使用DefaultAdvisorAutoProxyCreator,以及可以读取元数据属性的 Advisor。元数据细节定义在候选advisor的切入点部分,而不是自动代理创建类本身。

这是DefaultAdvisorAutoProxyCreator的一种特殊情况,但是它本身而言是值得考虑的。 (可以读取元数据的代码处于advisor的切入点中,而不是AOP框架本身。)

jPetStore示例应用的/attributes目录演示了属性驱动的自动代理的使用。在这个例子中, 没有必要使用TransactionProxyFactoryBean。仅仅在业务对象上定义业务属性就足够了,因为 使用了可知元数据的切入点。bean定义在/WEB-INF/declarativeServices.xml中,包括下 面的代码。注意这是通用的,可以在jPetStore以外的地方使用:

<bean id="autoproxy" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"> </bean> <bean id="transactionAttributeSource" class="org.springframework.transaction.interceptor.AttributesTransactionAttributeSource" autowire="constructor"> </bean> <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor" autowire="byType"> </bean> <bean id="transactionAdvisor" class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor" autowire="constructor" > </bean> <bean id="attributes" class="org.springframework.metadata.commons.CommonsAttributes" />

 DefaultAdvisorAutoProxyCreator bean定义--在这种情况下称作“advisor”,但是名字 无关紧要--会在当前的应用上午中选择所有符合的切入点。在这个例子中,类型为 TransactionAttributeSourceAdvisor的“transactionAdvisor”bean定义将会应用于包含事务属性 的类或方法。TransactionAttributeSourceAdvisor通过构造函数依赖于TransactionInterceptor。这个例子通过自动 装配来解析它。AttributesTransactionAttributeSource依赖于 org.springframework.metadata.Attributes接口的一个实现。在这段代码中,“attributes” bean使用Jakarta Commons Attributes API来获取属性信息。(应用代码必须使用Commons Attributes编译任务编译。)

这里定义的TransactionInterceptor依赖于一个 PlatformTransactionManager定义,它并没有被包括在这个通用的文件中(虽然应该是这样), 这是因为它是和应用的事务需求相关的(一般地,是想这个例子中的JTA,或者Hibernate,JDO 或JDBC):

<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager"/>
如果你只要求声明式事务管理,使用这些通用的XML定义就可以使得Spring自动代理含有事务属性的所有类和方法。 你不需要直接和AOP打交道,并且编程模型和.NET的ServicedComponents非常相似。
这个机制具有可扩展性。它可以基于定制的属性来使用自动代理。你需要:

定义你的定制属性。

指定的Advisor包含必要的通知和由方法或类的定制属性所触发的切入点。你可以使用已经存在的通知,仅仅实 现用来选择定制属性的切入点。

这些advisor可能对每个被通知类都是唯一的(例如,maxin)。它们仅仅需要被定义成 prototype bean,而不是singleton bean。例如,Spring的测试套件中的LockMixin 引入拦截器可以和一个属性驱动切入点一起来定位一个maxin,就象这里演示的。我们使用JavaBean配置的 普通的DefaultPointcutAdvisor:

<bean id="lockMixin" class="org.springframework.aop.LockMixin" singleton="false" /> <bean id="lockableAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor" singleton="false" > <property name="pointcut"> <ref local="myAttributeAwarePointcut"/> </property> <property name="advice"> <ref local="lockMixin"/> </property> </bean> <bean id="anyBean" class="anyclass" ...

如果知道属性的切入点符合anyBean或者其它bean定义中的任何方法,这个maxin 将被应用。注意,lockMixin和lockableAdvisor定义都是 prototype的。myAttributeAwarePointcut切入点可以被定义成singleton,因为它不为 不同的被通知对象保存状态。

0
相关文章