Spring原始碼解析(七):Spring AOP中對攔截器呼叫的實現
阿新 • • 發佈:2019-02-03
前面我們分析了Spring AOP實現中得到Proxy物件的過程,下面我們看看在Spring AOP中攔截器鏈是怎樣被呼叫的,也就是Proxy模式是怎樣起作用的,或者說Spring是怎樣為我們提供AOP功能的;
在JdkDynamicAopProxy中生成Proxy物件的時候:
Java程式碼
這裡的this引數對應的是InvocationHandler物件,這裡我們的JdkDynamicAopProxy實現了這個介面,也就是說當Proxy物件的函式被呼叫的時候,這個InvocationHandler的invoke方法會被作為回撥函式呼叫,下面我們看看這個方法的實現:
Java程式碼
我們先看看目標物件方法的呼叫,這裡是通過AopUtils的方法呼叫 - 使用反射機制來對目標物件的方法進行呼叫:
Java程式碼
對攔截器鏈的呼叫處理是在ReflectiveMethodInvocation裡實現的:
Java程式碼
這裡把當前的攔截器鏈以及在攔截器鏈的位置標誌都clone到一個MethodInvocation物件了,作用是當前的攔截器執行完之後,會繼續沿著得到這個攔截器鏈執行下面的攔截行為,也就是會迭代的呼叫上面這個proceed:
Java程式碼
這裡的nextInvocation就已經包含了當前的攔截鏈的基本資訊,我們看到在Interceptor中的實現比如TransactionInterceptor的實現中:
Java程式碼
從上面的分析我們看到了Spring AOP的基本實現,比如Spring怎樣得到Proxy,怎樣利用JAVA Proxy以及反射機制對使用者定義的攔截器鏈進行處理。
在JdkDynamicAopProxy中生成Proxy物件的時候:
Java程式碼
- return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
這裡的this引數對應的是InvocationHandler物件,這裡我們的JdkDynamicAopProxy實現了這個介面,也就是說當Proxy物件的函式被呼叫的時候,這個InvocationHandler的invoke方法會被作為回撥函式呼叫,下面我們看看這個方法的實現:
Java程式碼
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- MethodInvocation invocation = null;
- Object oldProxy = null;
- boolean setProxyContext = false;
- TargetSource targetSource = this.advised.targetSource;
-
Class targetClass = null
- Object target = null;
- try {
- // Try special rules for equals() method and implementation of the
- // Advised AOP configuration interface.
- if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
- // What if equals throws exception!?
-
// This class implements the equals(Object) method itself.
- return equals(args[0]) ? Boolean.TRUE : Boolean.FALSE;
- }
- if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
- // This class implements the hashCode() method itself.
- return new Integer(hashCode());
- }
- if (Advised.class == method.getDeclaringClass()) {
- // service invocations on ProxyConfig with the proxy config
- return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
- }
- Object retVal = null;
- 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.
- // 這裡是得到目標物件的地方,當然這個目標物件可能來自於一個例項池或者是一個簡單的JAVA物件
- target = targetSource.getTarget();
- if (target != null) {
- targetClass = target.getClass();
- }
- // get the interception chain for this method
- // 這裡獲得定義好的攔截器鏈
- List chain = this.advised.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
- this.advised, proxy, 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
- retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
- }
- else {
- // We need to create a method invocation...
- // invocation = advised.getMethodInvocationFactory().getMethodInvocation(
- // proxy, method, targetClass, target, args, chain, advised);
- // 如果有攔截器的設定,那麼需要呼叫攔截器之後才呼叫目標物件的相應方法
- // 這裡通過構造一個ReflectiveMethodInvocation來實現,下面我們會看這個ReflectiveMethodInvocation類
- invocation = new ReflectiveMethodInvocation(
- proxy, target, method, args, targetClass, chain);
- // proceed to the joinpoint through the interceptor chain
- // 這裡通過ReflectiveMethodInvocation來呼叫攔截器鏈和相應的目標方法
- retVal = invocation.proceed();
- }
- // massage return value if necessary
- if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy)) {
- // 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);
- }
- }
- }
我們先看看目標物件方法的呼叫,這裡是通過AopUtils的方法呼叫 - 使用反射機制來對目標物件的方法進行呼叫:
Java程式碼
- public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
- throws Throwable {
- // Use reflection to invoke the method.
- // 利用放射機制得到相應的方法,並且呼叫invoke
- try {
- if (!Modifier.isPublic(method.getModifiers()) ||
- !Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
- method.setAccessible(true);
- }
- 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("Couldn't access method: " + method, ex);
- }
- }
對攔截器鏈的呼叫處理是在ReflectiveMethodInvocation裡實現的:
Java程式碼
- public Object proceed() throws Throwable {
- // We start with an index of -1 and increment early.
- // 這裡直接呼叫目標物件的方法,沒有攔截器的呼叫或者攔截器已經呼叫完了,這個currentInterceptorIndex的初始值是0
- if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size()) {
- 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.
- // 這裡獲得相應的攔截器,如果攔截器可以匹配的上的話,那就呼叫攔截器的invoke方法
- InterceptorAndDynamicMethodMatcher dm =
- (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
- if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
- return dm.interceptor.invoke(nextInvocation());
- }
- else {
- // Dynamic matching failed.
- // Skip this interceptor and invoke the next in the chain.
- // 如果攔截器匹配不上,那就呼叫下一個攔截器,這個時候攔截器鏈的位置指示後移並迭代呼叫當前的proceed方法
- this.currentInterceptorIndex++;
- return proceed();
- }
- }
- else {
- // It's an interceptor, so we just invoke it: The pointcut will have
- // been evaluated statically before this object was constructed.
- return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(nextInvocation());
- }
- }
這裡把當前的攔截器鏈以及在攔截器鏈的位置標誌都clone到一個MethodInvocation物件了,作用是當前的攔截器執行完之後,會繼續沿著得到這個攔截器鏈執行下面的攔截行為,也就是會迭代的呼叫上面這個proceed:
Java程式碼
- private ReflectiveMethodInvocation nextInvocation() throws CloneNotSupportedException {
- ReflectiveMethodInvocation invocation = (ReflectiveMethodInvocation) clone();
- invocation.currentInterceptorIndex = this.currentInterceptorIndex + 1;
- invocation.parent = this;
- return invocation;
- }
這裡的nextInvocation就已經包含了當前的攔截鏈的基本資訊,我們看到在Interceptor中的實現比如TransactionInterceptor的實現中:
Java程式碼
- public Object invoke(final MethodInvocation invocation) throws Throwable {
- ......//這裡是TransactionInterceptor插入的事務處理程式碼,我們會在後面分析事務處理實現的時候進行分析
- try {
- //這裡是對配置的攔截器鏈進行迭代處理的呼叫
- retVal = invocation.proceed();
- }
- ......//省略了和事務處理的異常處理程式碼 ,也是TransactionInterceptor插入的處理
- else {
- try {
- Object result = ((CallbackPreferringPlatformTransactionManager) getTransactionManager()).execute(txAttr,
- new TransactionCallback() {
- public Object doInTransaction(TransactionStatus status) {
- //這裡是TransactionInterceptor插入對事務處理的程式碼
- TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointIdentification, status);
- //這裡是對配置的攔截器鏈進行迭代處理的呼叫,接著順著攔截器進行處理
- try {
- return invocation.proceed();
- }
- ......//省略了和事務處理的異常處理程式碼 ,也是TransactionInterceptor插入的處理
- }
從上面的分析我們看到了Spring AOP的基本實現,比如Spring怎樣得到Proxy,怎樣利用JAVA Proxy以及反射機制對使用者定義的攔截器鏈進行處理。