前置博文:
Spring AOP中如何为Bean创建代理?
Spring AOP中是如何注册Advisor的?
Spring AOP如何为目标方法创建拦截器链?
Spring AOP拦截器调用的实现
Spring AOP中CGLIB代理对象增强通知执行原理
在Spring AOP通过jdk的proxy方式或者CGLIB方式生成代理对象的时候,相关的拦截器已经配置到代理对象中去了,拦截器在代理对象中起作用是通过对这些方法的回调来完成的。
如果使用jdk的proxy来生成代理对象,那么需要通过InvocationHandler来设置拦截器回调。而如果使用CGLIB来生成代理对象,就需要根据CGLIB的使用要求,提供过DynamicAdvisedInterceptor来完成回调。
【1】JdkDynamicAopProxy的invoke拦截
JdkDynamicAopProxy 实现了AopProxy, InvocationHandler, Serializable接口,内部维护了AdvisedSupport advised成员。
那么也就是说当Proxy对象的代理方法被调用时,JdkDynamicAopProxy的invoke方法作为Proxy对象的回调函数被触发,从而通过invoke的具体实现,来完成对目标对象方法调用的拦截或者说功能增强的工作。
其invoke方法如下所示,对Proxy对象的代理设置是在invoke方法中完成的,这些设置包括获取目标对象、拦截器链,同时把这些对象作为输入创建了ReflectiveMethodInvocation对象,通过这个对象来完成对AOP功能实现的封装。
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// 如果目标对象没有实际object类的基本方法:equals
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
// 如果目标对象没有实际object类的基本方法:hashCode
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
//根据代理对象的配置来调用服务
else 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;
//将代理对象暴露给AopContext
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
// 得到目标对象的地方
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
// 这个很重要,获取拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a 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.
// 如果没有设定拦截器则直接调用target的对应方法
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 如果有拦截器的设定,那么需要调用拦截器之后才调用目标对象的相应方法
// 通过构造一个ReflectiveMethodInvocation赖世雄
// We need to create a method invocation...
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
// 沿着拦截器链继续前进
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.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;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
在这个invoke方法中,包含了一个完成的拦截器链对目标对象的拦截过程,比如获得拦截器链并对拦截器链中的拦截器进行配置,逐个运行拦截器链里的拦截增强,直到最后对目标对象方法的运行等。
【2】CglibAopProxy的intercept拦截
在分析CglibAopProxy
的代理对象生成的时候,我们了解到对于AOP的拦截调用其回调是在DynamicAdvisedInterceptor
对象中实现的,这个回调的实现在intercept方法中。
CglibAopProxy
的intercept回调方法的实现和JdkDynamicAopProxy
的回调实现是非常类似的,只是在DynamicAdvisedInterceptor
的intercept方法中构造的是CglibMethodInvocation
对象来完成拦截器链的调用,而在JdkDynamicAopProxy
中是通过构造ReflectiveMethodInvocation
对象来完成这个功能的。
需要注意点的是,CglibMethodInvocation是CglibAopProxy的静态内部类,继承于ReflectiveMethodInvocation重写了proceed方法。
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
// 暴露proxy给AopContext
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
// 获取target
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 核心方法,获取拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// 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.
// 如果拦截器链为空,则调用目标方法
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
// 这里通过methodProxy实现
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
// 封装CglibMethodInvocation 调用proceed,执行拦截器链
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
【3】目标对象方法的调用
如果没有设置拦截器,那么会对目标对象的方法直接进行调用。对于JdkDynamicAopProxy代理对象,这个对目标对象的方法调用是通过AopUtils使用反射机制在 AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse)
的方法中实现的。
代码如下所示,首先得到调用方法的反射对象,然后使用invoke启动对方法反射对象的调用。
public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)
throws Throwable {
// Use reflection to invoke the method.
try {
// 设置访问权限
ReflectionUtils.makeAccessible(method);
// 方法反射调用
return method.invoke(target, args);
}
catch (InvocationTargetException ex) {
// Invoked method threw a checked exception.
// We must rethrow it. The client won't see the interceptor.
throw ex.getTargetException();
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
method + "] on target [" + target + "]", ex);
}
catch (IllegalAccessException ex) {
throw new AopInvocationException("Could not access method [" + method + "]", ex);
}
}
对于使用CglibAopProxy代理对象,它对目标对象的调用是通过CGLIB的MethodProxy对象来直接完成的,这个对象的使用是由CGLIB的设计决定的。具体的调用在DynamicAdvisedInterceptor的intercept方法可以看到,使用的是CGLIB封装好的功能。相对JdkDynamicAopProxy的实现来说,形式上看起来较为简单,但它们的功能却是一样的,都是完成对目标对象方法的调用。
retVal = methodProxy.invoke(target, argsToUse);
// org.springframework.cglib.proxy.MethodProxy#invoke
public Object invoke(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f1.invoke(fci.i1, obj, args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
catch (IllegalArgumentException ex) {
if (fastClassInfo.i1 < 0)
throw new IllegalArgumentException("Protected method: " + sig1);
throw ex;
}
}
【4】AOP拦截器链的调用
AOP对目标对象增强是通过将实现封装在AOP拦截器链中,由一个个具体的拦截器完成的。对于jdk和CGLIB两种方式来言,虽然使用了不同的AopProxy代理对象,但最终对AOP拦截的处理可谓殊途同归:它们对拦截器链的调用都是在ReflectiveMethodInvocation的proceed方法实现的。在proceed方法中,会逐个运行拦截器的拦截方法。
在运行拦截器的拦截方法之前,需要对代理方法完成一个匹配判断,通过这个匹配判断来决定拦截器是否满足切面增强的要求。即我们熟知的Pointcut切点中需要进行matches的匹配过程,即matches调用对方法进行匹配判断,来决定是否需要实行通知增强。
如下代码所示,在proceed方法中,先进行判断如果现在已经运行到拦截器链的末尾,俺么就会直接调用目标对象的实现方法。否则,沿着拦截器链继续进行,得到下一个拦截器。通过这个拦截器进行matches判断,判断是否适用于横切增强的场合。如果是,从拦截器得到通知器,并启动通知器的invoke方法进行切面增强。在这个过程结束以后,会迭代调用proceed凡那个发,直到拦截器链当中的拦截器都完成以上的拦截过程为止。
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// 从索引为-1的拦截器开始调用,并按序递增;
//如果拦截器链中拦截器均执行完,这里调用目标对象的方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 沿着定义好的拦截器链进行处理
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
// 如果不匹配则递归调用proceed
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
// 如果是一个Interceptor,直接调用这个Interceptor对应的方法
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}