在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); } }