`
zpball
  • 浏览: 916956 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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

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

        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);


这里的this参数对应的是InvocationHandler对象,这里我们的JdkDynamicAopProxy实现了这个接口,也就是说当Proxy对象的函数被调用的时候,这个InvocationHandler的invoke方法会被作为回调函数调用,下面我们看看这个方法的实现:

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

    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的方法调用 - 使用反射机制来对目标对象的方法进行调用:

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

    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里实现的:
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());   
    }   
}  

    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:
private ReflectiveMethodInvocation nextInvocation() throws CloneNotSupportedException {   
    ReflectiveMethodInvocation invocation = (ReflectiveMethodInvocation) clone();   
    invocation.currentInterceptorIndex = this.currentInterceptorIndex + 1;   
    invocation.parent = this;   
    return invocation;   
}  

    private ReflectiveMethodInvocation nextInvocation() throws CloneNotSupportedException {
        ReflectiveMethodInvocation invocation = (ReflectiveMethodInvocation) clone();
        invocation.currentInterceptorIndex = this.currentInterceptorIndex + 1;
        invocation.parent = this;
        return invocation;
    }


这里的nextInvocation就已经包含了当前的拦截链的基本信息,我们看到在Interceptor中的实现比如TransactionInterceptor的实现中:

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插入的处理   
   }  

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

相关推荐

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

    在Spring AOP中,拦截器调用的实现是通过动态代理机制来完成的,主要涉及到JDK的Proxy类和InvocationHandler接口。本文将详细解析Spring AOP如何利用这两个组件来实现拦截器链的调用。 首先,Spring在生成代理对象...

    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源码学习文档,绝对值得好好研究~~

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

    spring源代码解析

    "spring源代码解析(五):spring AOP获得proxy.doc"和"spring源代码解析(七):spring AOP中对拦截器调用的实现.doc"详细解释了AOP代理的生成过程,以及Aspect的实现和通知的执行流程。 5. **事务管理**:"spring...

    Spring源代码解析(五):Spring_AOP获取Proxy.doc

    在Spring框架中,AOP(面向切面编程)是一种强大的工具,它允许程序员在不修改原有业务代码的情况下,插入额外的逻辑或监控行为。本文将深入解析Spring AOP如何获取代理对象,即Proxy。 首先,我们需要理解AOP的...

    spring aop 拦截器简单实现

    Spring AOP(面向切面编程)是Spring框架中的一个重要特性,它允许我们在不修改源代码的情况下,通过代理机制对程序进行扩展和增强。本例提供了一个简单的AOP拦截器实现,我们可以从这个基础出发,深入理解和探讨AOP...

    Spring源代码解析(六):Spring声明式事务处理.doc

    在整个源代码分析中,我们可以看到 Spring 实现声明式事务管理有三个部分: 1. 对在上下文中配置的属性的处理,这里涉及的类是 TransactionAttributeSourceAdvisor,这是一个通知器,用它来对属性值进行处理,属性...

    ssh+aop+log4j+日志拦截器+注解

    4. 日志拦截器:在Java中,日志拦截器通常是指通过AOP来实现的对特定方法调用进行日志记录的机制。它可以在方法执行前、执行后或异常时插入日志打印,帮助开发者跟踪程序运行状态,尤其在多线程和复杂业务逻辑中非常...

    详解Spring AOP 拦截器的基本实现

    具体到Spring AOP拦截器的代码实现,本文通过创建TestInterceptor类来演示。这个类继承自HandlerInterceptorAdapter,然后重写其中的afterCompletion、postHandle等方法。在这个类中,可以在相应方法中添加自定义的...

    Spring使用AOP的三个jar包

    Spring的AOP框架就是基于这些接口构建的,这样开发者可以编写一次拦截器,就可以在多个AOP框架中复用。 这三个jar包在Spring AOP中的角色如下: 1. `aspectjrt.jar`:提供AspectJ的运行时支持,用于实现基于...

    Spring aop代码

    Spring AOP(面向切面编程)是Spring框架中的一个重要组成部分,它允许程序员在不修改源代码的情况下,通过插入切面来增强程序的功能。这个压缩包文件"Spring AOP代码"很可能包含了一些示例代码,用于演示如何在...

    SpringAOP的日志拦截示例

    总结来说,Spring AOP的日志拦截通过定义拦截器、切入点和顾问,可以方便地实现对特定方法的透明日志记录。这个示例中的`LogInterceptor.java`实现了具体拦截逻辑,而`config.xml`则负责配置拦截规则,两者结合实现...

    spring aop demo 两种实现方式

    Spring AOP(面向切面编程)是Spring框架的重要组成部分,它允许程序员在不修改源代码的情况下,对应用程序的特定部分(如方法调用)进行拦截和处理。这为日志、事务管理、性能监控等提供了方便。本示例提供了一种...

    Spring+SpringMvc+MybatisPlus+Aop(自定义注解)动态切换数据源

    在这个项目中,我们利用自定义的Aop注解来实现数据源的动态切换。自定义注解可以附加在方法上,当该方法被调用时,AOP会捕获这个调用并执行相应的逻辑,即切换到指定的数据源。 具体实现步骤如下: 1. 定义数据源...

Global site tag (gtag.js) - Google Analytics