7.8. 操作被通知对象

在创建了AOP代理之后,你能够使用org.springframework.aop.framework.Advised接口对它们进行管理。 任何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的切入点。因此如果你曾经加入一个MethodInterceptor, 返回的通知器将是一个DefaultPointcutAdvisor,它可以返回你加入的MethodInterceptor和一个匹配所有类和方法的切入点。

addAdvisor()方法可以用来添加任何通知器。通常保存切入点和通知的通知器是DefaultPointcutAdvisor,它可以用于任何通知或切入点(但不包括引入类型)。

缺省情况下,你可以加入或移除通知器或者拦截器甚至当代理已经被创建之后。唯一的限制是无法加入或者移除一个引入通知器,因为工厂中获得的已有代理不能显示接口的改变(你可以通过从工厂里获取一个新的代理来避免这个问题)。

下面是一个简单的例子,它把一个AOP代理转型为Advised接口,检查并操作它的通知:

Advised advised = (Advised) myObject;
            Advisor[] advisors = advised.getAdvisors();
            int oldAdvisorCount = advisors.length;
            System.out.println(oldAdvisorCount + " advisors");
            
            // Add an advice like an interceptor without a pointcut
            // Will match all proxied methods
            // Can use for interceptors, before, after returning or throws advice
            advised.addAdvice(new DebugInterceptor());
            
            // Add selective advice using a pointcut
            advised.addAdvisor(new DefaultPointcutAdvisor(mySpecialPointcut, myAdvice));
            
            assertEquals("Added two advisors",
        oldAdvisorCount + 2, advised.getAdvisors().length);

注意

在一个实际运行的系统里,修改一个业务对象上的通知是否明智是个问题,虽然无疑在某些情况下这样做是合理的。然而这在开发中是很有用的: 例如,在测试的时候。对于希望测试的方法调用,有时我发现把测试代码加入到一个拦截器或者其它通知里是非常有用的。 (例如,通知可以与目标方法存在于同一个事务里,在把事务标记为回滚之前可以用SQL来检查数据库是否被正确的更新了。)

依赖于你怎样创建代理,你通常可以设置一个 frozen标志,在这种情况下 AdvisedisFrozen()方法将返回true,任何增加或者移除通知的修改都会导致一个AopConfigException异常。 在某些情况下这种冻结被通知对象状态的能力是很有用的:例如,防止调用代码来移除一个进行安全检查的拦截器。在Spring 1.1中它也被用来允许激进优化,如果已经知道不需要运行时对通知进行修改的话。