• Spring源代码解析(七):Spring AOP中对拦截器调用的实现


    前面我们分析了Spring AOP实现中得到Proxy对象的过程,下面我们看看在Spring AOP中拦截器链是怎样被调用的,也就是Proxy模式是怎样起作用的,或者说Spring是怎样为我们提供AOP功能的; 
    在JdkDynamicAopProxy中生成Proxy对象的时候: 
    Java代码  收藏代码
    1. return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);  

    这里的this参数对应的是InvocationHandler对象,这里我们的JdkDynamicAopProxy实现了这个接口,也就是说当Proxy对象的函数被调用的时候,这个InvocationHandler的invoke方法会被作为回调函数调用,下面我们看看这个方法的实现: 
    Java代码  收藏代码
    1. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
    2.     MethodInvocation invocation = null;  
    3.     Object oldProxy = null;  
    4.     boolean setProxyContext = false;  
    5.   
    6.     TargetSource targetSource = this.advised.targetSource;  
    7.     Class targetClass = null;  
    8.     Object target = null;  
    9.   
    10.     try {  
    11.         // Try special rules for equals() method and implementation of the  
    12.         // Advised AOP configuration interface.  
    13.   
    14.         if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {  
    15.             // What if equals throws exception!?  
    16.             // This class implements the equals(Object) method itself.  
    17.             return equals(args[0]) ? Boolean.TRUE : Boolean.FALSE;  
    18.         }  
    19.         if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {  
    20.             // This class implements the hashCode() method itself.  
    21.             return new Integer(hashCode());  
    22.         }  
    23.         if (Advised.class == method.getDeclaringClass()) {  
    24.             // service invocations on ProxyConfig with the proxy config  
    25.             return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);  
    26.         }  
    27.   
    28.         Object retVal = null;  
    29.   
    30.         if (this.advised.exposeProxy) {  
    31.             // make invocation available if necessary  
    32.             oldProxy = AopContext.setCurrentProxy(proxy);  
    33.             setProxyContext = true;  
    34.         }  
    35.   
    36.         // May be <code>null</code>. Get as late as possible to minimize the time we "own" the target,  
    37.         // in case it comes from a pool.  
    38.         // 这里是得到目标对象的地方,当然这个目标对象可能来自于一个实例池或者是一个简单的JAVA对象  
    39.         target = targetSource.getTarget();  
    40.         if (target != null) {  
    41.             targetClass = target.getClass();  
    42.         }  
    43.   
    44.         // get the interception chain for this method  
    45.         // 这里获得定义好的拦截器链  
    46.         List chain = this.advised.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(  
    47.                 this.advised, proxy, method, targetClass);  
    48.   
    49.         // Check whether we have any advice. If we don't, we can fallback on direct  
    50.         // reflective invocation of the target, and avoid creating a MethodInvocation.  
    51.         // 如果没有设定拦截器,那么我们就直接调用目标的对应方法  
    52.         if (chain.isEmpty()) {  
    53.             // We can skip creating a MethodInvocation: just invoke the target directly  
    54.             // Note that the final invoker must be an InvokerInterceptor so we know it does  
    55.             // nothing but a reflective operation on the target, and no hot swapping or fancy proxying  
    56.             retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);  
    57.         }  
    58.         else {  
    59.             // We need to create a method invocation...  
    60.             // invocation = advised.getMethodInvocationFactory().getMethodInvocation(  
    61.             //         proxy, method, targetClass, target, args, chain, advised);  
    62.             // 如果有拦截器的设定,那么需要调用拦截器之后才调用目标对象的相应方法  
    63.             // 这里通过构造一个ReflectiveMethodInvocation来实现,下面我们会看这个ReflectiveMethodInvocation类  
    64.             invocation = new ReflectiveMethodInvocation(  
    65.                     proxy, target, method, args, targetClass, chain);  
    66.   
    67.             // proceed to the joinpoint through the interceptor chain  
    68.             // 这里通过ReflectiveMethodInvocation来调用拦截器链和相应的目标方法  
    69.             retVal = invocation.proceed();  
    70.         }  
    71.   
    72.         // massage return value if necessary  
    73.         if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy)) {  
    74.             // Special case: it returned "this" and the return type of the method is type-compatible  
    75.             // Note that we can't help if the target sets  
    76.             // a reference to itself in another returned object.  
    77.             retVal = proxy;  
    78.         }  
    79.         return retVal;  
    80.     }  
    81.     finally {  
    82.         if (target != null && !targetSource.isStatic()) {  
    83.             // must have come from TargetSource  
    84.             targetSource.releaseTarget(target);  
    85.         }  
    86.   
    87.         if (setProxyContext) {  
    88.             // restore old proxy  
    89.             AopContext.setCurrentProxy(oldProxy);  
    90.         }  
    91.     }  
    92. }  

    我们先看看目标对象方法的调用,这里是通过AopUtils的方法调用 - 使用反射机制来对目标对象的方法进行调用: 
    Java代码  收藏代码
    1. public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)  
    2.     throws Throwable {  
    3.   
    4.     // Use reflection to invoke the method.  
    5.     // 利用放射机制得到相应的方法,并且调用invoke  
    6.     try {  
    7.         if (!Modifier.isPublic(method.getModifiers()) ||  
    8.                 !Modifier.isPublic(method.getDeclaringClass().getModifiers())) {  
    9.             method.setAccessible(true);  
    10.         }  
    11.         return method.invoke(target, args);  
    12.     }  
    13.     catch (InvocationTargetException ex) {  
    14.         // Invoked method threw a checked exception.  
    15.         // We must rethrow it. The client won't see the interceptor.  
    16.         throw ex.getTargetException();  
    17.     }  
    18.     catch (IllegalArgumentException ex) {  
    19.         throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +  
    20.                 method + "] on target [" + target + "]", ex);  
    21.     }  
    22.     catch (IllegalAccessException ex) {  
    23.         throw new AopInvocationException("Couldn't access method: " + method, ex);  
    24.     }  
    25. }  

    对拦截器链的调用处理是在ReflectiveMethodInvocation里实现的: 
    Java代码  收藏代码
    1. public Object proceed() throws Throwable {  
    2.     //    We start with an index of -1 and increment early.  
    3.     // 这里直接调用目标对象的方法,没有拦截器的调用或者拦截器已经调用完了,这个currentInterceptorIndex的初始值是0  
    4.     if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size()) {  
    5.         return invokeJoinpoint();  
    6.     }  
    7.   
    8.     Object interceptorOrInterceptionAdvice =  
    9.         this.interceptorsAndDynamicMethodMatchers.get(this.currentInterceptorIndex);  
    10.     if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {  
    11.         // Evaluate dynamic method matcher here: static part will already have  
    12.         // been evaluated and found to match.  
    13.         // 这里获得相应的拦截器,如果拦截器可以匹配的上的话,那就调用拦截器的invoke方法  
    14.         InterceptorAndDynamicMethodMatcher dm =  
    15.             (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;  
    16.         if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {  
    17.             return dm.interceptor.invoke(nextInvocation());  
    18.         }  
    19.         else {  
    20.             // Dynamic matching failed.  
    21.             // Skip this interceptor and invoke the next in the chain.  
    22.             // 如果拦截器匹配不上,那就调用下一个拦截器,这个时候拦截器链的位置指示后移并迭代调用当前的proceed方法  
    23.             this.currentInterceptorIndex++;  
    24.             return proceed();  
    25.         }  
    26.     }  
    27.     else {  
    28.         // It's an interceptor, so we just invoke it: The pointcut will have  
    29.         // been evaluated statically before this object was constructed.  
    30.         return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(nextInvocation());  
    31.     }  
    32. }  

    这里把当前的拦截器链以及在拦截器链的位置标志都clone到一个MethodInvocation对象了,作用是当前的拦截器执行完之后,会继续沿着得到这个拦截器链执行下面的拦截行为,也就是会迭代的调用上面这个proceed: 
    Java代码  收藏代码
    1. private ReflectiveMethodInvocation nextInvocation() throws CloneNotSupportedException {  
    2.     ReflectiveMethodInvocation invocation = (ReflectiveMethodInvocation) clone();  
    3.     invocation.currentInterceptorIndex = this.currentInterceptorIndex + 1;  
    4.     invocation.parent = this;  
    5.     return invocation;  
    6. }  

    这里的nextInvocation就已经包含了当前的拦截链的基本信息,我们看到在Interceptor中的实现比如TransactionInterceptor的实现中: 
    Java代码  收藏代码
    1. public Object invoke(final MethodInvocation invocation) throws Throwable {  
    2.    ......//这里是TransactionInterceptor插入的事务处理代码,我们会在后面分析事务处理实现的时候进行分析  
    3.         try {  
    4.             //这里是对配置的拦截器链进行迭代处理的调用  
    5.             retVal = invocation.proceed();  
    6.         }  
    7.    ......//省略了和事务处理的异常处理代码 ,也是TransactionInterceptor插入的处理  
    8.       else {  
    9.         try {  
    10.             Object result = ((CallbackPreferringPlatformTransactionManager) getTransactionManager()).execute(txAttr,  
    11.                     new TransactionCallback() {  
    12.                         public Object doInTransaction(TransactionStatus status) {  
    13.                              //这里是TransactionInterceptor插入对事务处理的代码  
    14.                             TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointIdentification, status);  
    15.                             //这里是对配置的拦截器链进行迭代处理的调用,接着顺着拦截器进行处理  
    16.                             try {                          
    17.                                 return invocation.proceed();  
    18.                             }  
    19.    ......//省略了和事务处理的异常处理代码 ,也是TransactionInterceptor插入的处理  
    20.    }  

    从上面的分析我们看到了Spring AOP的基本实现,比如Spring怎样得到Proxy,怎样利用JAVA Proxy以及反射机制对用户定义的拦截器链进行处理。 
  • 相关阅读:
    VMware Workstation网卡不启动
    解决IE10以下对象不支持“bind”属性或方法
    二分法查找
    选择排序与冒泡排序
    方法内部开启线程的方法
    重写Collections实现自定义排序
    根据反射生成SQL语句
    vue插件安装备忘
    vue cli4.x 新建项目 过程提醒
    php setcooike()失败的原因之一,希望能帮到你
  • 原文地址:https://www.cnblogs.com/chenying99/p/2709158.html
Copyright © 2020-2023  润新知