共计 3264 个字符,预计需要花费 9 分钟才能阅读完成。
1、Advice 与 MethodInterceptor
Advice 是被某个切面在特定的连接点采取的操作。Spring 提供了多种 Advice,能够不便扩大。Advice 的类型包含 around(盘绕 advice)、before(前置 advice)和 after(后置 advice)。在 Spring 中将 Advice 建模为一个 Interceptor。下图是 Spring 中罕用的 Advice 的继承图。
![](/img/bVc9oW8)
图中的 Advice 接口时整个 Advice 体系的根接口,Advice 接口的全门路的类名是:org.aopalliance.aop.Advice。这个类是 Aop 联盟定义的类。
Advice 的子类带有 Aspectj 结尾,这些类是包装 Aspectj 注解的 advice 办法。
Spring 反对仅反对办法级别的链接点,因而 Spring 的 Advice 最终都会通过 MethodInterceptor 来执行 invoke 办法。
Object invoke(@Nonnull MethodInvocation invocation) throws Throwable;
那么可能会有疑难,图中的 AspectJMethodBeforeAdvice 没有实现 MethodInterceptor,那么是怎么实现 Advice 操作的呢?Advise 和 Pointcut 一起组成了 Advisor,Spring 在创立代理对象的时候会查找所有实用对象办法的 Advisor,而后通过 Advisor 创立出 MethodInterceptor, 具体代码能够参考:AdvisorAdapter 及其实现。
明天咱们要介绍的是 Introduction Advice。
Introduction Advice(引入告诉)
Spring 看待 introduction advice 作为一种非凡的拦挡告诉.
引入(Introduction) 须要一个 IntroductionAdvisor 和一个实现接口 IntroductionInterceptor 的类。
public interface IntroductionInterceptor extends MethodInterceptor {boolean implementsInterface(Class intf);
}
继承自 MethodInterceptor 接口的 invoke() 办法须要实现引入性能。也就是说,如果调用的办法切实一个引入接口办法,引入拦截器负责解决办法调用,而不须要调用连接点的 proceed();
Introduction advice 不能和任何 pointcut 应用,因为它仅实用于类,而不是办法级别。只能用 IntroductionAdvisor 来应用 introduction advice。
public interface IntroductionAdvisor extends Advisor, IntroductionInfo {ClassFilter getClassFilter();
void validateInterfaces() throws IllegalArgumentException;}
public interface IntroductionInfo {Class<?>[] getInterfaces();}
getInterfaces() 办法返回被这个 Advisor 对象引入的接口。
validateInterfaces() 办法被外部用来查看引入的接口是否被配置的 IntroductionInterceptor 来实现。
来看一个 Spring test 套件的例子,假如咱们想将以下接口引入到一个或者很多个对象中:
public interface Lockable {void lock();
void unlock();
boolean locked();}
这个例子解释了一个混入的实现。咱们想要将一个无论任何类型的类转换为 Lockable,并能调用 lock() 和 unlock() 办法。如果咱们调用 lock() 办法,咱们想要实现所有的 setter 办法会抛出 LockedException. 因而,咱们能够通过一个切面来提供在对一个对象毫不理解的状况下来实现不可变的性能。
首先,咱们须要实现一个 IntroductionInterceptor 来实现这个艰巨工作。咱们能够通过扩大 org.springframework.aop.support.DelegatingIntroductionInterceptor 便当类。当然咱们也能够间接实现 IntroductionInterceptor, 然而应用 DelegatingIntroductionInterceptor 在大多数状况下是最好的抉择。
DelegatingIntroductionInterceptor 旨在将介绍委托给所引入接口的实在实现,从而暗藏了拦挡的应用。能够通过结构参数设置任意类型的代理。默认的代理(结构参数没有参数的话)是 this 对象。因而,在这个例子中,代理对象是实现 LockMixin 的子类 DelegatingIntroductionInterceptor。
public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable {
private boolean locked;
public void lock() {this.locked = true;}
public void unlock() {this.locked = false;}
public boolean locked() {return this.locked;}
public Object invoke(MethodInvocation invocation) throws Throwable {if (locked() && invocation.getMethod().getName().indexOf("set") == 0) {throw new LockedException();
}
return super.invoke(invocation);
}
}
给定一个代理(默认是 this 对象),DelegatingIntroductionInterceptor 实例查找这个代理实现的所有接口(除了 IntroductionInterceptor),并且通过他们反对引入。LockMixin 能够通过调用 suppressInterface 办法来勾销不应该被裸露的接口。
然而,无论一个 IntroductionInterceptor 筹备反对多少个接口,IntroductionAdvisor 都会管制理论裸露哪些接口。引入的接口暗藏了指标对同一接口的任何实现.
LockMixin 扩大了 DelegatingIntroductionInterceptor 并且实现了 Lockable。父类(DelegatingIntroductionInterceptor)主动查看到 Lockable 接口能够被反对引入,咱们不须要特地指定。通常不须要覆写 invoke() 办法。DelegatingIntroductionInterceptor 的实现(如果办法是引入办法,那么调用代理办法,否则持续返回连接点)基本上就满足了。在 LockMixIn 例子中,,invoke() 办法进行了一个 set 办法检测。
public class LockMixinAdvisor extends DefaultIntroductionAdvisor {public LockMixinAdvisor() {super(new LockMixin(), Lockable.class);
}
}
通常引入告诉的 Advisor 是 per-instance(每一个代理对象对应一个 Advisor 实例),认为引入是有状态的。如何管制 per-instance,在 Advisor 的 isPerInstance()中有解释,应用 sigleton 和 prototype 范畴的 bean 定义或者适当的代理创立编程。