操作被通知对象
无论你如何创建 AOP 代理,你都可以通过使用 infra.aop.framework.Advised 接口来操作它们。
任何 AOP 代理都可以转换为此接口,无论它实现了哪些其他接口。此接口包括以下方法:
-
Java
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() 方法为已添加到工厂的每个 advisor、interceptor 或其他 advice 类型返回一个 Advisor。
如果你添加了一个 Advisor,则在此索引处返回的 advisor 就是你添加的对象。
如果你添加了一个 interceptor 或其他 advice 类型,Infra 会将其包装在一个 pointcut 始终返回 true 的 advisor 中。
因此,如果你添加了一个 MethodInterceptor,则为此索引返回的 advisor 是一个 DefaultPointcutAdvisor,
它返回你的 MethodInterceptor 和一个匹配所有类和方法的 pointcut。
addAdvisor() 方法可用于添加任何 Advisor。通常,持有 pointcut 和 advice 的 advisor 是通用的 DefaultPointcutAdvisor,
你可以将其与任何 advice 或 pointcut 一起使用(但不能用于引介)。
默认情况下,即使已创建代理,也可以添加或删除 advisor 或 interceptor。 唯一的限制是无法添加或删除引介 advisor,因为工厂中的现有代理不会显示接口更改。 (你可以从工厂获取新代理以避免此问题。)
以下示例显示了将 AOP 代理转换为 Advised 接口并检查和操作其 advice:
-
Java
Advised advised = (Advised) myObject;
Advisor[] advisors = advised.getAdvisors();
int oldAdvisorCount = advisors.length;
System.out.println(oldAdvisorCount + " advisors");
// 添加像拦截器这样的 advice,没有 pointcut
// 将匹配所有代理方法
// 可以用于 interceptor、前置、返回后或抛出 advice
advised.addAdvice(new DebugInterceptor());
// 使用 pointcut 添加选择性 advice
advised.addAdvisor(new DefaultPointcutAdvisor(mySpecialPointcut, myAdvice));
assertEquals("Added two advisors", oldAdvisorCount + 2, advised.getAdvisors().length);
| 在生产环境中修改业务对象上的 advice 是否明智(没有双关语意)是值得商榷的,尽管毫无疑问存在合法的使用案例。 但是,它在开发中非常有用(例如,在测试中)。我们有时发现能够以拦截器或其他 advice 的形式添加测试代码非常有用, 可以进入我们要测试的方法调用内部。(例如,advice 可以进入为该方法创建的事务中,也许在运行 SQL 以检查数据库是否正确更新之前, 将事务标记为回滚。) |
根据你创建代理的方式,通常可以设置 frozen 标志。
在这种情况下,Advised isFrozen() 方法返回 true,任何通过添加或删除修改 advice 的尝试都会导致 AopConfigException。
冻结被通知对象状态的能力在某些情况下很有用(例如,防止调用代码删除安全拦截器)。