在上一篇文章 spring AOP源碼分析(二)中,我們已經知道如何生成一個代理對象了,那么當代理對象調用代理方法時,增強行為也就是攔截器是如何發揮作用的呢?接下來我們將介紹JDK動態代理和cglib這兩種方式下,攔截器調用的實現。
一 JDK動態代理攔截器調用的實現:
我們知道,在生成代理對象時,相關的攔截器已經配置到代理對象中了。Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); 這行代碼是用於生成代理對象的,this代表InvocationHandler接口,此處是指JdkDynamicAopProxy類,
因為JdkDynamicAopProxy實現了InvocationHandler接口。當生成的代理對象調用代理方法時,會觸發InvocationHandler接口中invoke方法的調用,而增強行為的發生或者說對目標對象方法的攔截動作就是在這個方法中。我們進入JdkDynamicAopProxy
類的invoke方法:
/** * Implementation of {@code InvocationHandler.invoke}. * <p>Callers will see exactly the exception thrown by the target, * unless a hook method throws an exception. */ @Override 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 {
// 如果目標對象沒有實現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; 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); // 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. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else {
// 否則,需要先調用攔截器然后再調用目標方法,通過構造一個ReflectiveMethodInvocation來實現 // We need to create a method invocation... 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); } } }
當沒有攔截器時,我們進入invokeJoinpointUsingReflection這個方法,可以看到通過反射的方式直接調用目標對象方法
/** * Invoke the given target via reflection, as part of an AOP method invocation. * @param target the target object * @param method the method to invoke * @param args the arguments for the method * @return the invocation result, if any * @throws Throwable if thrown by the target method * @throws org.springframework.aop.AopInvocationException in case of a reflection error */ public static Object invokeJoinpointUsingReflection(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); } }
當有攔截器時,我們進入invocation.proceed()方法,這個方法就是AOP的核心部分了,AOP是如何完成對目標對象的增強的?這些實現封裝在AOP攔截器鏈中,由一個個具體的攔截器實現的,就在這個方法中。
@Override 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.
// 這里是觸發匹配判斷的地方,如果和定義的pointcut匹配,那么這個advice將得到執行 InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // Dynamic matching failed. // Skip this interceptor and invoke the next in the chain. 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的invoke方法 進入此方法來分析通知(攔截器)是如何起作用的 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
進入MethodBeforeAdviceInterceptor類的invoke方法,就是前置通知調用的方法:
@Override public Object invoke(MethodInvocation mi) throws Throwable { this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); // 此處就是發生的切面增強行為 return mi.proceed(); //遞歸調用proceed方法,然后進入下一個攔截器的處理 }
進入AspectJAfterAdvice類的invoke方法,就是后置通知調用的方法:
@Override public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); //遞歸調用proceed方法 } finally { invokeAdviceMethod(getJoinPointMatch(), null, null); //此處就是發生切面增強行為的地方 } }
接下來我們考慮另外一個問題:在xml中定義的通知是如何配置到代理對象中的攔截器鏈中的?
我們知道,我們是通過 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);這行代碼獲取攔截器的,所以所有的攔截器都在interceptorsAndDynamicMethodMatchers這個list集合中,那么
這個集合從哪個地方獲取的呢?我們可以進入JdkDynamicAopProxy類的invoke方法,有這么一行代碼:List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);用於獲取這個代理方法的攔截器鏈,進入此方法:
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
// 這里使用cache獲取已有的interceptor鏈,如果是第一次,需要手動生成,這里是使用AdvisorChainFactory來生成interceptor鏈的,默認是DefaultAdvisorChainFactory MethodCacheKey cacheKey = new MethodCacheKey(method); List<Object> cached = this.methodCache.get(cacheKey); if (cached == null) { cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this, method, targetClass); this.methodCache.put(cacheKey, cached); } return cached; }
DefaultAdvisorChainFactory 由名字可知,這是一個生成通知器鏈的工廠。進入getInterceptorsAndDynamicInterceptionAdvice這個方法:
@Override public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, Class<?> targetClass) { // 所有的advistor在config中已經持有了,可以直接使用 // This is somewhat tricky... We have to process introductions first, // but we need to preserve order in the ultimate list. List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length); Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); boolean hasIntroductions = hasMatchingIntroductions(config, actualClass); AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); for (Advisor advisor : config.getAdvisors()) { if (advisor instanceof PointcutAdvisor) { // Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
//通過AdvisorAdapterRegistry注冊器,把從config中獲取的advistor進行適配,從而獲得攔截器,再把它放入List中。這就是攔截器注冊的過程。 MethodInterceptor[] interceptors = registry.getInterceptors(advisor); MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) { if (mm.isRuntime()) { // Creating a new object instance in the getInterceptors() method // isn't a problem as we normally cache created chains. for (MethodInterceptor interceptor : interceptors) { interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); } } else { interceptorList.addAll(Arrays.asList(interceptors)); } } } } else if (advisor instanceof IntroductionAdvisor) { IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; }
以上就是JDK動態代理springAOP實現增強行為的過程,對於cglib這種方式,此處就不做分析。