无论你如何创建 AOP 代理,你都可以通过使用 org.springframework.aop.framework.Advised接口来操作它们。任何 AOP 代理都可以被投到这个接口,不管它实现了哪些其他接口。这个接口包括以下方法:

    1. Advisor[] getAdvisors();
    2. void addAdvice(Advice advice) throws AopConfigException;
    3. void addAdvice(int pos, Advice advice) throws AopConfigException;
    4. void addAdvisor(Advisor advisor) throws AopConfigException;
    5. void addAdvisor(int pos, Advisor advisor) throws AopConfigException;
    6. int indexOf(Advisor advisor);
    7. boolean removeAdvisor(Advisor advisor) throws AopConfigException;
    8. void removeAdvisor(int index) throws AopConfigException;
    9. boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;
    10. boolean isFrozen();

    getAdvisors() 方法为每个顾问、拦截器或其他已添加到工厂的顾问类型返回一个顾问。如果你添加了一个顾问,在这个索引处返回的顾问就是你添加的对象。如果你添加了一个拦截器或其他 advice 类型,Spring 将其包装在一个顾问中,并有一个总是返回 true 的指针。因此,如果你添加了一个 MethodInterceptor,这个索引返回的顾问是一个 DefaultPointcutAdvisor,它返回你的 MethodInterceptor 和一个匹配所有类和方法的 pointcut。

    addAdvisor()方法可以用来添加任何顾问。通常,持有 pointcut 和 advice 的顾问是通用的 DefaultPointcutAdvisor,你可以将其用于任何 advice 或 pointcut(但不用于 introductions )。

    默认情况下,即使代理被创建后,也可以添加或删除顾问或拦截器。唯一的限制是不可能添加或删除引入(introductions )顾问,因为现有的来自工厂的代理不显示接口的变化。(你可以从工厂获得一个新的代理来避免这个问题)。

    下面的例子显示了将一个 AOP 代理投到 Advised 接口,并检查和操作它的 advice :

    1. Advised advised = (Advised) myObject;
    2. Advisor[] advisors = advised.getAdvisors();
    3. int oldAdvisorCount = advisors.length;
    4. System.out.println(oldAdvisorCount + " advisors");
    5. // 添加一个像拦截器一样的 advice,没有 切入点的 advice
    6. // 将与所有被代理的方法相匹配
    7. // 可用于拦截器,在返回或 异常 advice 之前、之后。
    8. advised.addAdvice(new DebugInterceptor());
    9. // 添加一个有 切入点 + advice 的顾问
    10. advised.addAdvisor(new DefaultPointcutAdvisor(mySpecialPointcut, myAdvice));
    11. assertEquals("Added two advisors", oldAdvisorCount + 2, advised.getAdvisors().length);

    :::info 在生产中修改业务对象的 advice 是否可取(无双关之意)是值得怀疑的,尽管毫无疑问有合法的使用案例。然而,它在开发中可能非常有用(例如,在测试中)。我们有时发现,能够以拦截器或其他 advice 的形式添加测试代码,进入我们想要测试的方法调用中,是非常有用的。(例如,advice 可以进入为该方法创建的事务中,也许是运行 SQL 来检查数据库是否被正确更新,然后再标记事务进行回滚)。 :::

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