6.7. 操作通知对象

但是,您可以通过使用org.springframework.aop.framework.Advised接口来创建AOP代理,从而对其进行操作。任何AOP代理都可以强制转换到此接口,不管它实现了哪个其他接口。此接口包括以下方法:

Advisor[] getAdvisors();

void addAdvice(Advice advice) throws AopConfigException;

void addAdvice(int pos, Advice advice) throws AopConfigException;

void addAdvisor(Advisor advisor) throws AopConfigException;

void addAdvisor(int pos, Advisor advisor) throws AopConfigException;

int indexOf(Advisor advisor);

boolean removeAdvisor(Advisor advisor) throws AopConfigException;

void removeAdvisor(int index) throws AopConfigException;

boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;

boolean isFrozen();

getAdvisors() 方法返回已添加到工厂的每个顾问、拦截器或其他通知类型的顾问。如果添加了顾问,则此索引处返回的顾问是您添加的对象。如果您添加了一个拦截器或其他通知类型,那么Spring将它包装在一个顾问中,并使用一个始终返回true的切入点。因此,如果添加了一个SystemInterceptor,则为该索引返回的Advisor是一个返回SystemInterceptor的DefaultPointcutAdvisor,以及一个匹配所有类和方法的切入点。
addAdvisor() 方法可用于添加任何顾问。通常,持有切入点和建议的顾问是通用的默认切入点顾问,您可以将其用于任何建议或切入点(但不用于介绍)。
默认情况下,即使创建了代理,也可以添加或删除顾问或拦截器。唯一的限制是不可能添加或删除introduction顾问,因为工厂的现有代理不显示接口更改。(您可以从工厂获取新代理以避免此问题。)
下面的示例显示将AOP代理强制转换到通知的接口,并检查和操作其通知

Advised advised = (Advised) myObject;
Advisor[] advisors = advised.getAdvisors();
int oldAdvisorCount = advisors.length;
System.out.println(oldAdvisorCount + " advisors");

//添加一个类似于没有切入点的拦截器的通知将匹配所有方法,可用于拦截器,before, after returning或者 throws通知。
advised.addAdvice(new DebugInterceptor());

// 使用切入点添加选择性建议
advised.addAdvisor(new DefaultPointcutAdvisor(mySpecialPointcut, myAdvice));

assertEquals("Added two advisors", oldAdvisorCount + 2, advised.getAdvisors().length);
尽管无疑存在合法的使用案例,但是否建议(不打算使用双关语)修改生产中业务对象的建议仍然存在疑问。但是,它在开发中非常有用。我们有时发现,能够以拦截器或其他通知的形式添加测试代码,进入我们想要测试的方法调用中是非常有用的。(例如,在将事务标记为回滚之前,通知可以进入为该方法创建的事务中,或者运行SQL检查数据库是否正确更新。)

根据创建代理的方式,通常可以设置 freeze 标志。在这种情况下,Advised的isFrozen()方法返回true,任何通过添加或删除来修改通知的尝试都会导致AOPConfigException。在某些情况下(例如,为了防止调用代码删除安全拦截器),冻结通知对象的状态的功能非常有用。

6.8.使用“自动代理”功能

到目前为止,我们已经考虑通过使用ProxyFactoryBean n或类似的工厂bean显式地创建AOP代理。
Spring还允许我们使用“自动代理”bean定义,它可以自动代理选定的bean定义。这是在Spring的“bean后处理器”基础设施上构建的,它支持在容器加载时修改任何bean定义。
在这个模型中,您在XML bean定义文件中设置了一些特殊的bean定义,以配置自动代理基础结构。这允许您声明符合自动代理条件的目标。您不需要使用ProxyFactoryBean。
有两种方法可以做到这一点:

  • 通过使用在当前上下文中引用特定bean的自动代理创建者。
  • 一个需要单独考虑的自动代理创建的特殊情况:由源代码级元数据属性驱动的自动代理创建。

6.8.1.自动代理bean定义

本节介绍由本节介绍由org.springframework.aop.framework.auto proxy包提供的自动代理创建者。
BeanNameAutoProxyCreator
BeannameAutoProxyCreator类是一个BeanPostProcessor,它自动为名称与文字值或通配符匹配的Bean创建AOP代理。下面的示例演示如何创建BeannameAutoProxyCreator bean

<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属性而不是一个拦截器列表,以允许原型顾问的正确行为。命名的“拦截器”可以是顾问或任何通知类型。
与一般的自动代理一样,使用BeanNameAutoProxyCreator的主要目的是将相同的配置一致地应用于多个对象,配置量最小。它是将声明性事务应用于多个对象的常用选择。
名称匹配的bean定义(如前面示例中的jdkMyBean和onlyJdk)是带有目标类的普通旧bean定义。AOP代理由BeanNameAutoProxyCreator自动创建。同样的通知也适用于所有匹配的bean。注意,如果使用顾问(而不是前面示例中的拦截器),则切入点可能会不同地应用于不同的bean。
DefaultAdvisorAutoProxyCreator
一个更通用和非常强大的自动代理创建者是DefaultAdvisorAutoProxyCreator。这将在当前上下文中自动应用合格的顾问,而不需要在自动代理顾问的bean定义中包含特定的bean名称。它提供了与BeanNameAutoProxyCreator相同的配置和避免重复的优点。
使用此机制涉及:

  • 指定DefaultAdvisorAutoProxyCreator bean定义。
  • 在相同或相关的上下文中指定任意数量的顾问。请注意,这些必须是顾问,而不是拦截器或其他知道。这是必要的,因为必须有一个切入点来评估,以检查每个建议对候选bean定义的合格性。

DefaultAdvisorAutoProxyCreator自动评估每个顾问中包含的切入点,以查看它应该应用于每个业务对象(如示例中的BusinessObject1和BusinessObject2)的建议(如果有)。
这意味着任何数量的顾问都可以自动应用于每个业务对象。如果任何顾问中没有与业务对象中的任何方法匹配的切入点,则不会代理该对象。当为新的业务对象添加bean定义时,如果需要,它们将被自动代理。
一般来说,自动代理的优点是使调用者或依赖项无法获得未通知的对象。在此ApplicationContext上调用getBean("businessObject1")将返回AOP代理,而不是目标业务对象。(前面显示的“内部bean”习语也提供了这个好处。)
下面的示例创建一个DefaultAdvisorAutoProxyCreatorbean和本节讨论的其他元素:

<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非常有用。一旦基础结构定义就位,就可以添加新的业务对象,而不包括特定的代理配置。您还可以通过对配置的最小更改轻松地进入其他方面(例如,跟踪或性能监视方面)。

DefaultAdvisorAutoProxyCreator支持过滤(通过使用命名约定,只评估某些顾问,从而允许在同一工厂中使用多个不同配置的AdvisorAutoProxyCreators)和排序。顾问可以实现org.springframework.core.Ordered接口,以确保在出现问题时正确排序。在前面的示例中使用的TransactionAttributeSourceAdvisor有可配置的顺序值。默认设置是无序的。