`

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以及反射机制对用户定义的拦截器链进行处理。

分享到:
评论

相关推荐

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

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

    Spring源代码解析.rar

    Spring源代码解析7:Spring AOP中对拦截器调用的实现 .doc Spring源代码解析8:Spring驱动Hibernate的实现.doc Spring源代码解析9:Spring Acegi框架鉴权的实现.doc Spring源代码解析10:Spring Acegi框架授权的实现...

    Spring 源代码解析

    Spring源代码解析7:Spring AOP中对拦截器调用的实现 Spring源代码解析8:Spring驱动Hibernate的实现;Spring源代码解析9:Spring Acegi框架鉴权的实现 Spring源代码解析10:Spring Acegi框架授权的实现

    Spring源代码解析

    Spring源代码解析(七):Spring AOP中对拦截器调用的实现 Spring源代码解析(八):Spring驱动Hibernate的实现 Spring源代码解析(九):Spring Acegi框架鉴权的实现 Spring源代码解析(十):Spring Acegi框架授权...

    springyuanmaaping.zip

    pring源代码解析1:IOC容器;Spring源代码解析2:IoC容器在Web容器中的启动;Spring源代码解析3:... Spring源代码解析7:Spring AOP中对拦截器调用的实现 Spring源代码解析8:Spring驱动Hibernate的实现;Spring源代

    spring源码分析(1-10)

    Spring源代码解析(七):Spring AOP中对拦截器调用的实现 Spring源代码解析(八):Spring驱动Hibernate的实现 Spring源代码解析(九):Spring Acegi框架鉴权的实现 Spring源代码解析(十):Spring Acegi框架授权...

    spring源码分析

    Spring源代码解析(七):Spring AOP中对拦截器调用的实现 8. Spring源代码解析(八):Spring驱动Hibernate的实现 9.Spring源代码解析(九):Spring Acegi框架鉴权的实现 10. Spring源代码解析(十):Spring ...

    Spring源码学习文档,绝对值得好好研究~~

    Spring源代码解析(七):Spring AOP中对拦截器调用的实现.doc Spring源代码解析(八):Spring驱动Hibernate的实现.doc Spring源代码解析(九):Spring Acegi框架鉴权的实现.doc Spring源代码解析(十):Spring ...

    Spring-Reference_zh_CN(Spring中文参考手册)

    13.4.3. 拦截器(HandlerInterceptor) 13.5. 视图与视图解析 13.5.1. 视图解析器 13.5.2. 视图解析链 13.5.3. 重定向(Rediret)到另一个视图 13.5.3.1. RedirectView 13.5.3.2. redirect:前缀 13.5.3.3. forward:...

    Spring中文帮助文档

    13.4.3. 拦截器(HandlerInterceptor) 13.5. 视图与视图解析 13.5.1. 视图解析器(ViewResolver) 13.5.2. 视图解析链 13.5.3. 重定向(Rediret)到另一个视图 13.6. 本地化解析器 13.6.1. ...

    Spring API

    13.4.3. 拦截器(HandlerInterceptor) 13.5. 视图与视图解析 13.5.1. 视图解析器(ViewResolver) 13.5.2. 视图解析链 13.5.3. 重定向(Rediret)到另一个视图 13.6. 本地化解析器 13.6.1. ...

    Spring 2.0 开发参考手册

    13.4.3. 拦截器(HandlerInterceptor) 13.5. 视图与视图解析 13.5.1. 视图解析器 13.5.2. 视图解析链 13.5.3. 重定向(Rediret)到另一个视图 13.6. 本地化解析器 13.6.1. AcceptHeaderLocaleResolver 13.6.2....

    spring chm文档

    13.4.3. 拦截器(HandlerInterceptor) 13.5. 视图与视图解析 13.5.1. 视图解析器 13.5.2. 视图解析链 13.5.3. 重定向(Rediret)到另一个视图 13.6. 本地化解析器 13.6.1. AcceptHeaderLocaleResolver 13.6.2....

    Spring面试题

    4.容器提供了AOP技术,利用它很容易实现如权限拦截,运行期监控等功能 5.容器提供了众多的辅助类,能加快应用的开发 6.spring对于主流的应用框架提供了集成支持,如hibernate,JPA,Struts等 7.spring属于低侵入...

    Spring in Action(第二版 中文高清版).part2

    11.3.4 使用注释声明拦截器 11.4 小结 第12章 访问企业服务 12.1 从JNDI中获取对象 12.1.1 使用传统的JNDI 12.1.2 注入JNDI对象 12.1.3 在Spring 2中注入JNDI对象 12.2 发送电子邮件 12.2.1 配置邮件发送...

    Spring in Action(第二版 中文高清版).part1

    11.3.4 使用注释声明拦截器 11.4 小结 第12章 访问企业服务 12.1 从JNDI中获取对象 12.1.1 使用传统的JNDI 12.1.2 注入JNDI对象 12.1.3 在Spring 2中注入JNDI对象 12.2 发送电子邮件 12.2.1 配置邮件发送...

    Spring in Action(第2版)中文版

    11.3.4使用注释声明拦截器 11.4小结 第12章访问企业服务 12.1从jndi中获取对象 12.1.1使用传统的jndi 12.1.2注入jndi对象 12.1.3在spring2中注入jndi对象 12.2发送电子邮件 12.2.1配置邮件发送器 12.2.2...

    Spring Security 中文教程.pdf

    1.4.2. 获得源代码 2. Security命名空间配置 2.1. 介绍 2.1.1. 命名空间的设计 2.2. 开始使用安全命名空间配置 2.2.1. 配置web.xml 2.2.2. 最小 &lt;http&gt; 配置 2.2.2.1. auto-config 包含了什么? 2.2...

    spring security 参考手册中文版

    25.1 AOP联盟(MethodInvocation)安全拦截器 197 25.1.1显式MethodSecurityInterceptor配置 197 25.2 AspectJ(JoinPoint)安全拦截器 198 26.基于表达式的访问控制 200 26.1概述 200 26.1.1通用内置表达式 201 ...

Global site tag (gtag.js) - Google Analytics