操纵被通知对象

无论您如何创建AOP代理,您都可以通过使用org.springframework.aop.framework.Advised接口来操纵它们。任何AOP代理都可以转换为此接口,无论它实现了哪些其他接口。此接口包括以下方法:

  • Java

  • Kotlin

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();
fun getAdvisors(): Array<Advisor>

@Throws(AopConfigException::class)
fun addAdvice(advice: Advice)

@Throws(AopConfigException::class)
fun addAdvice(pos: Int, advice: Advice)

@Throws(AopConfigException::class)
fun addAdvisor(advisor: Advisor)

@Throws(AopConfigException::class)
fun addAdvisor(pos: Int, advisor: Advisor)

fun indexOf(advisor: Advisor): Int

@Throws(AopConfigException::class)
fun removeAdvisor(advisor: Advisor): Boolean

@Throws(AopConfigException::class)
fun removeAdvisor(index: Int)

@Throws(AopConfigException::class)
fun replaceAdvisor(a: Advisor, b: Advisor): Boolean

fun isFrozen(): Boolean

getAdvisors()方法为每个已添加到工厂的顾问、拦截器或其他建议类型返回一个Advisor。如果您添加了一个Advisor,则在此索引处返回的顾问是您添加的对象。如果您添加了一个拦截器或其他建议类型,Spring会将其包装在一个具有始终返回true的切入点的顾问中。因此,如果您添加了一个MethodInterceptor,则此索引返回的顾问是一个DefaultPointcutAdvisor,它返回您的MethodInterceptor和一个匹配所有类和方法的切入点。

addAdvisor()方法可用于添加任何Advisor。通常,持有切入点和建议的顾问是通用的DefaultPointcutAdvisor,您可以将其与任何建议或切入点一起使用(但不能用于引入)。

默认情况下,即使创建了代理,也可以添加或删除顾问或拦截器。唯一的限制是无法添加或删除引入顾问,因为工厂中的现有代理不显示接口更改。(您可以从工厂获取新代理以避免此问题。)

以下示例显示将AOP代理转换为Advised接口,并检查和操纵其建议:

  • Java

  • Kotlin

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);
val advised = myObject as Advised
val advisors = advised.advisors
val oldAdvisorCount = advisors.size
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(DebugInterceptor())

// Add selective advice using a pointcut
advised.addAdvisor(DefaultPointcutAdvisor(mySpecialPointcut, myAdvice))

assertEquals("Added two advisors", oldAdvisorCount + 2, advised.advisors.size)
在生产环境中修改业务对象的建议是否明智尚存疑问(无意冒犯),尽管毫无疑问存在合法的使用情况。但在开发中(例如在测试中),这可能非常有用。我们有时发现能够添加测试代码(例如拦截器或其他建议)非常有用,以便进入我们想要测试的方法调用内部。(例如,建议可以进入为该方法创建的事务内部,也许运行SQL以检查数据库是否正确更新,然后标记事务以进行回滚。)

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