无论你如何创建 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()
方法为每个顾问、拦截器或其他已添加到工厂的顾问类型返回一个顾问。如果你添加了一个顾问,在这个索引处返回的顾问就是你添加的对象。如果你添加了一个拦截器或其他 advice 类型,Spring 将其包装在一个顾问中,并有一个总是返回 true 的指针。因此,如果你添加了一个 MethodInterceptor,这个索引返回的顾问是一个 DefaultPointcutAdvisor,它返回你的 MethodInterceptor 和一个匹配所有类和方法的 pointcut。
addAdvisor()
方法可以用来添加任何顾问。通常,持有 pointcut 和 advice 的顾问是通用的 DefaultPointcutAdvisor,你可以将其用于任何 advice 或 pointcut(但不用于 introductions )。
默认情况下,即使代理被创建后,也可以添加或删除顾问或拦截器。唯一的限制是不可能添加或删除引入(introductions )顾问,因为现有的来自工厂的代理不显示接口的变化。(你可以从工厂获得一个新的代理来避免这个问题)。
下面的例子显示了将一个 AOP 代理投到 Advised 接口,并检查和操作它的 advice :
Advised advised = (Advised) myObject;
Advisor[] advisors = advised.getAdvisors();
int oldAdvisorCount = advisors.length;
System.out.println(oldAdvisorCount + " advisors");
// 添加一个像拦截器一样的 advice,没有 切入点的 advice
// 将与所有被代理的方法相匹配
// 可用于拦截器,在返回或 异常 advice 之前、之后。
advised.addAdvice(new DebugInterceptor());
// 添加一个有 切入点 + advice 的顾问
advised.addAdvisor(new DefaultPointcutAdvisor(mySpecialPointcut, myAdvice));
assertEquals("Added two advisors", oldAdvisorCount + 2, advised.getAdvisors().length);
:::info 在生产中修改业务对象的 advice 是否可取(无双关之意)是值得怀疑的,尽管毫无疑问有合法的使用案例。然而,它在开发中可能非常有用(例如,在测试中)。我们有时发现,能够以拦截器或其他 advice 的形式添加测试代码,进入我们想要测试的方法调用中,是非常有用的。(例如,advice 可以进入为该方法创建的事务中,也许是运行 SQL 来检查数据库是否被正确更新,然后再标记事务进行回滚)。 :::
根据你创建代理的方式,你通常可以设置一个冻结标志。在这种情况下,Advised isFrozen()
方法返回 true,任何试图通过添加或删除来修改 advice 的行为都会导致 AopConfigException。冻结 advice 对象的状态的能力在某些情况下是有用的(例如,防止调用代码删除安全拦截器)。