Spring AOP之横切逻辑的执行
AOP横切逻辑的执行
AOP横切逻辑的执行主要由一个接口来执行AopProxy,它有两个实现JdkDynamicAopProxy和Cglib2AopProxy,Spring会根据不同的情况选择不同的AopProxy来执行横切逻辑,先来看一下JdkDynamicAopProxy的一个情况:
JdkDynamicAopProxy
看下JdkDynamicAopProxy的Invoke方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class targetClass = null;
Object target = null;
try {
// equals hashcode等方法处理
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 检查拦截器链是否为空,如果为空,就直接通过反射调用目标对象的方法,避免创建多余的MethodInvocation对象
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
// 创建一个MethodInvocation
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 通过拦截器链调用切面逻辑
retVal = invocation.proceed();
}
// Massage return value if necessary.
if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
以上这个方法的重点是:invocation.proceed()方法,这个方法是通过递归的方式来调用拦截器链里面的每一个拦截器,我们看一下这个方法的具体实现:
public Object proceed() throws Throwable {
// 从-1开始,然后先加
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 如果上一次调用的已经是最后一个拦截器,则调用切面逻辑
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// 动态方法匹配
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// 动态方法匹配失败,然后直接调用拦截器链的下一个拦截器
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// 非动态方法匹配,静态方法匹配,之前已经匹配过,这是一个拦截器,直接调用
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
单看这一段代码还看不出递归影子,看下MethodInterceptor的各个实现类的invoke方法便可以看到,虽然MethodInterceptor的实现类对于invoke方法的具体实现有所不同,然是它们都调用了mi.proceed()这个方法,从而实现对拦截器链的递归调用。
Cglib2AopProxy
Cglib调用横切逻辑的方式和Jdk基本相似,代码上区别在于调用的方法不一样那个,Cglib2AopProxy调用的是其内部类DynamicAdvicedInterceptor中的intercept方法:
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be <code>null</code>. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool.
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// 检查是否只是有一个InvokerInterceptor:没有真正的Advice,直接反射调用目标方法
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// 跳过创建MethodInvocation的步骤:直接调用目标方法
// 注意最后一个invoker必须使一个InvokerInterceptor,这样我们才能知道它并没有做任何事情,只是对目标做了一个反射操作
retVal = methodProxy.invoke(target, args);
}
else {
// 创建一个MethodInvocation并调用
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = massageReturnTypeIfNecessary(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
从这段代码中可以看出,Cglib2AopProxy是创建了一个CglibMethodInvocation并调用其proceed()方法,而CglibMethodInvocation是继承了RefectiveMethodInvocation,所以最后还是调用了ReflectiveMethodInvocation的proceed()方法。但是CglibMethodInvocation重写了ReflectiveMethodInvocation的invokeJoinpoint()方法,按照作者写的注释似乎能带来微小的性能提升:
/**
* Gives a marginal performance improvement versus using reflection to
* invoke the target when invoking public methods.
*/
protected Object invokeJoinpoint() throws Throwable {
if (this.protectedMethod) {
return super.invokeJoinpoint();
}
else {
return this.methodProxy.invoke(this.target, this.arguments);
}
}