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

Spring AOP 源码实现过程

 
阅读更多

        我们看看在Spring AOP中拦截器链是怎样被调用的,也就是Proxy模式是怎样起作用的,或者说Spring是怎样为我们提供AOP功能的; 

在JdkDynamicAopProxy中生成Proxy对象的时候: 

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) {   
            targettargetClass = 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);   
    }   
}   

 对拦截器链的调用处理是在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());   
    }   
}   

       这里把当前的拦截器链以及在拦截器链的位置标志都clone到一个MethodInvocation对象了,作用是当前的拦截器执行完之后,会继续沿着得到这个拦截器链执行下面的拦截行为,也就是会迭代的调用上面这个proceed: 

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

从上面的分析我们看到了Spring AOP的基本实现,比如Spring怎样得到Proxy,怎样利用JAVA Proxy以及反射机制对用户定义的拦截器链进行处理。

 

分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    Java spring AOP源码

    ### Java Spring AOP源码分析 #### 概述 在探讨Spring AOP源码之前,我们首先需要了解Spring AOP的基本概念以及它的工作原理。面向切面编程(Aspect-Oriented Programming, AOP)是一种编程范式,它通过将横切关注...

    Spring AOP IOC源码笔记.pdf

    Spring AOP基于代理实现,可以使用接口代理(JDK动态代理)或类代理(CGLIB)。 7. CGLIB: CGLIB是Spring AOP默认的代理库,用于生成目标类的子类,从而实现方法拦截。当目标类没有实现接口时,Spring会使用CGLIB...

    五、Spring源码分析——Spring Aop

    了解了Spring AOP的基本概念后,我们可以进一步深入源码,探究如何创建代理、如何执行通知以及如何实现切点匹配。这对于理解Spring的工作原理,以及优化和扩展Spring AOP功能具有重要意义。 在实际开发中,Spring ...

    spring aop 自定义注解保存操作日志到mysql数据库 源码

    一、适合人群 1、具备一定Java编程基础,初级开发者 ...(需要知道原理的请看spring aop源码,此处不做赘述) 3、可在现有源码上快速进行功能扩展 4、spring boot,mybatis,druid,spring aop的使用

    Spring_aop源码

    Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象...

    AOP流程源码分析-SpringAOP中定义的类图

    AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析...

    spring源码--AOP流程--笔记.docx

    Spring AOP 源码分析笔记 Spring AOP(Aspect-Oriented Programming)是一种编程范式,它允许开发者 modularize cross-cutting concerns,即将横切关注点模块化。AOP 使得开发者可以将一些公共的功能模块化,以便在...

    Spring AOP实现 项目源码 Myeclipse 直接导入可用

    本项目源码提供了在Myeclipse环境中直接导入并运行的示例,旨在帮助开发者深入理解Spring AOP的实现。 **一、Spring AOP 知识点** 1. **切面(Aspect)**: 切面是程序中的一个关注点,如日志、事务等。在Spring ...

    spring aop 源码解析

    总结来说,Spring AOP的源码解析涉及到多个组件的协同工作,包括代理工厂、切入点解析器、通知实现以及织入机制。通过对这些关键组件的理解,我们可以更好地掌握Spring AOP的工作原理,从而在实际开发中更加灵活地...

    spring-aop源码

    总结,Spring AOP源码的探索有助于开发者深入理解面向切面编程的实现机制,提升问题解决能力,从而更好地利用AOP技术优化和维护应用程序。通过实践与学习,我们可以更好地驾驭这个强大的工具,提高代码的可维护性和...

    Spring AOP源码分析.mmap

    下面我们接着来看AOP的源码实现。 有关于AOP,我们在面试中也被无数次问到,AOP是什么?AOP有什么作用与优势?AOP在项目中是如何用到的? 这些还都是比较简单的,有些可能会问你AOP的实现是怎样的? 哪怕...

    Spring源码最难问题:当Spring AOP遇上循环依赖.docx

    Spring源码最难问题:当Spring AOP遇上循环依赖 Spring源码中最难的问题之一是循环依赖问题,当Spring AOP遇上循环依赖时,该如何解决? Spring通过三级缓存机制解决循环依赖的问题。 在Spring中,bean的实例化...

    Java流行框架源码分析:Spring源码、SpringBoot源码、SpringAOP源码、SpringSecurity源码、

    Java流行框架源码分析:Spring源码、SpringBoot源码、SpringAOP源码、SpringSecurity源码、SpringSecurity OAuth2源码、JDK源码、Netty源码

    Spring AOP框架实现的结构分析

    最后,本文的目标是从实现的角度来认识 SpringAOP 框架,观察的角度是从外部接口、内部实现、组成部分、执行过程四个方面来认识 SpringAOP 框架。本文的风格是首先列出 AOP 的基本概念,然后介绍框架所涉及到的核心...

    spring aop实现原理

    NULL 博文链接:https://zhang-yingjie-qq-com.iteye.com/blog/319927

    反射实现 AOP 动态代理模式(Spring AOP 的实现 原理) - Java 例子 -

    Spring框架是Java中实现AOP的一个流行工具,它通过动态代理机制实现了这一功能。本文将深入探讨Spring AOP的实现原理,以及如何使用反射来实现动态代理模式。 首先,我们需要了解AOP的基本概念。AOP的核心思想是切...

    Spring Aop 源码流程.doc

    当我们谈论Spring AOP的源码流程,这通常涉及到Spring初始化过程中的自动代理创建,以及如何通过AOP实现切面的动态代理。下面我们将深入探讨这个过程。 首先,Spring容器的初始化始于`...

    简单spring aop 例子

    本示例将简要介绍如何在Spring应用中实现AOP,通过实际的代码示例帮助理解其工作原理。 首先,我们要理解AOP的核心概念。AOP是一种编程范式,它允许开发者定义“切面”(Aspects),这些切面封装了特定的关注点,如...

    Spring AOP例子实现源码

    在`springAop`目录下,你应该会看到如`LoggingAspect.java`这样的源码文件,它实现了切面逻辑。此外,可能还有一个`Main`类用于启动应用程序并演示AOP如何工作。通过运行这个示例,你可以观察到切面是如何在运行时...

    Java进阶之SpringAOP源码深度剖析共17页.pd

    通过对Spring AOP源码的深入分析,我们可以了解到其内部是如何通过代理模式和反射技术实现对方法调用的拦截,以及如何解析和执行切点表达式,理解通知的执行流程等。这些深入理解对于优化性能、排查问题以及自定义...

Global site tag (gtag.js) - Google Analytics