SEARU.ORG
当前位置:SEARU.ORG > Linux 新闻 > 正文

Spring 源码分析(三) —— AOP(一)AOP原理

AOP概论

        AOP(Aspect-Oriented Programming,面向切面的编程),谈起AOP,则一定会追溯到OOP(Object Oriented Programming,面向对象编程),因为AOP可以说是对OOP的补充和完善,而这一切的理念都是从模块化开始的。OOP是一种非常成功、极具表现力的编程范式,它将概念自然地表达为对象,从而将其中通用的代码模块化。所以,衡量OOP成功与否的标准就是它在多大程度上避免了代码的重复。一般情况下,OOP能够很好地避免代码重复。具体继承可以帮助我们在不同类型之间共享相同的行为;多态让我们可以用同样的方式来处理不同类型之间的对象,能够让我们将注意力集中在他们的共同之处。但当遇上一些特定问题的时候,比如,当我们需要为分散的对象引入公共行为时,OOP就显得很无力了。也就是说,OOP很适合你定义从上到下的关系,但不适合定义水平的关系。可以说因为有这些Bug的存在,是AOP生成的直接诱因,所以是为了弥补OOP而存在的。AOP在看待应用程序结构的方式上与OOP是截然不同的,以AOP的思路来看,系统是被分解成方面(Aspect)或者关注点(Concern),而不是一个个对象。追根溯源,与OOP一样,AOP只不过是一种全新的模块化机制而已,他的主要作用是用来描述分散在对象、类或函数中的横切关注点,从关注点中分离出横切关注点则是 AOP的核心概念。

        AOP的原理,也是非常简单的,即通过分离关注点让解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中就不再含有针对特定领域问题代码的调用,业务逻辑同特定领域问题的关系则通过切面来封装、维护,这样原本分散在整个应用程序中的代码就可以很好的进行管理了。例如:在使用公共函数的时候,往往需要进行一些逻辑设计,也就时需要代码实现来支持,而这些逻辑代码也是需要维护的,在传统的公共子模块的调用中,除了直接调用以外就没有其他的手段。而相同的情况,在使用AOP后,不仅可以将这些重复的代码抽出来单独维护,而且可以在需要时进行统一调度,这样的使用方法虽然与设计公共子模块有几分相似,但他为这一类问题的解决提供了一整套完整的理论和灵活多样的实现方法。也就是说,在AOP提出横切概念以后,再把模块功能正交化的同时,也在此基础上提供了一系列横切的灵活实现。

        

AOP体系

       实现原理

         在编译期修改源代码、运行期节码加载前修改字节码或字节码加载后动态创建代理类的节码,这是AOP的具体实现方法,而他是由三个重要步骤来完成的,先是生成代理对象,然后是拦截器的作用,最后是编织的具体实现。AOP框架的丰富,其实很大程度上体现在这三个步骤上所具有的丰富技术选择,以及与IOC容器之间的无缝缝合。而如果以实现方法来分的话,则主要有两类:静态AOP(包括静态织入)和动态AOP(包含动态代理、动态节码生成、自定义类加载器、节码转换器)。

       结构概述

        除了通过使用Proxy代理对象、拦截器字节码翻译技术等一系列已有的AOP或者AOP实现技术,来实现切面应用的各种编织实现和环绕增强以外。还成立了AOP联盟来探索AOP的标准化,希望借此来推动AOP的发展。而对于现在已有的AOP实现方案,AOP联盟对它们进行了一定程度的抽象,从而定义出了AOP的体系结构。结合这个AOP体系结构去了解AOP技术是非常有帮助的,AOP联盟定义的AOP体系结构如图所示:

        AOP联盟定义的AOP体系结构把与AOP相关的概念大致分为由高到低、从使用到实现的三个层次。从上往下:

        最高层是语言和开发环境,在这个环境中可以看到几个重要的概念:“基础”可以视为待增强对象或者说目标对象;“切面”通常包含对于基础的增强应用;“配置”可以看成是一种编织,通过在AOP体系中提供这个配置环境,可以把基础和切面结合起来,从而完成切面对目标对象的编织实现。

        AOP体系结构的第二层次为语言和开发环境提供支持的,在这个层次中可以看到AOP框架的高层实现,主要包括配置和编织实现两部分内容。例如配置逻辑和编织逻辑实现本身,以及对这些实现进行抽象的一些高层API封装。这些实现和API封装,为前面提到的语言和开发环境的实现提供了有力的支持。

        最底层是编织的具体实现模块,各种技术都可以作为编织逻辑的具体实现方法,比如反射、程序预处理、拦截器框架、类装载器框架、元数据处理等等。


       使用概况

        AOP在 权限(Authentication)、缓存(Cache)、内容传递(Context passing)、错误处理(Error handling)、懒加载(Lazy loading)、调试(Debug)、日志(Log)、跟踪优化和校准(tracing、profiling and monitoring)、性能优化(Performance optimization)、持久化(Persistence)、资源池(Resource pooling)、同步(Synchronization)、事务(Transactions)等方面都有用处,可以说是可使用范围及广。下面我们就以一张思维导图来串联,以此来铺开与AOP相关的所有的知识点。

                AOP通常包含以下相关术语:

                        1、目标对象(Target):包含连接点的对象。也被用来引用增强化或代理化对象。

                        2、代理(Proxy):AOP 框架创建的对象,包含增强。

                        3、连接点(Joinpoint):程序执行过程中明确的点,如方法的调用或特定的异常被抛出。

                        4、切点(Pointcut):指定一个通知将被引发的一系列连接点。AOP 框架必须允许开发者指定切入点:例如,使用正则表达式。

                        5、增强(Advice):在特定的连接点AOP框架执行的动作。各种类型的增强包括“around”、“before”、“throws”增强等等。增强类型将在下面讨论。许多 AOP 框架都是以拦截器做增强模型,维护一个“围绕”连接点的拦截器链。

                        6、切面(Advisor):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事物管理是J2EE应用中横切关注点中一个很好的例子。切面一般是用 Advisor 或者 拦截器实现。

                        7、织入(Weaving):组装方面创建通知化对象。这可以在编译时完成(例如:使用AspectJ编译器),也可以在运行时完成。Spring 和其他一些纯 Java AOP 框架,使用运行时织入。

                        8、引入(Introduction):添加方法或字段到增强化类。

                        9、接口(IsModified):用于简化缓存。(这里作为补充)。


                AOP增强类型(也叫 通知类型)包括:

                        1、Before Advice(前置增强):在一个连接点之前执行的增强,但这个增强不能阻止流程继续执行到连接点(除非它抛出一个异常)。

                        2、After Advice(后增强,全称是 After returning advice 正常返回增强 ):在连接点正常完成后执行的增强,例如,如果一个正常返回,没有抛出异常。如果抛出异常则不会执行。

                        3、Around Advice(环绕增强):包围一个连接点的增强,如方法调用,是最强大的增强。在方法调用前后完成自定义的行为。它们负责选择继续执行连接点或直接返回它们自己的返回值或抛出异常来执行。

                        4、Throws Advice(抛出增强,全称是 After throwing advice 异常返回增强,也叫 Finally returning advice 最终返回增强是最常用的增强类型。大部分是基于拦截器框架如Nanning或者JBoss4提供的Around增强。作用是,不管,是否正常执行,都会返回增强中的内容。

                        5、Introduction Advice(引入增强):一种非常特殊的增强。它将新的成员变量、成员方法引入到目标类中。它仅能作用于类层次,而不是方法层次,所以他不能作用于任何切入点。


‍‍Spring AOP 实现原理

        AOP模块是Spring的核心模块,尽管Spring中有自己的一套AOP实现,但在Java社区中是最完整AOP框架还是Aspectj,所以为了弥补自己的不足,也为了提供更加丰富的AOP解决方案,Spring对Aspectj做了集成。同时,再配合Spring的IOC容器,Spring推出了一个完善的AOP解决方法。

        Spring AOP的核心技术是JDK的动态代理技术。Spring AOP是以动态代理技术为基础,设计出了一系列AOP的横切实现,比如:前置增强、返回增强、异常增强等等。同时,Spring AOP还提供了一系列的Pointcut来匹配切入点,可以使用现有的切入点来设计横切面,也可以扩展相关的Pointcut方法来切入需求。

        Spring AOP 中,我们一般是通过配置文件或者编程的方式来实现的。常见的配置方法有四种:1,配置 ProxyFactoryBean 显示设置 advisors、advice、target 等。2,配置 AutoProxyCreator 这种方式下,还是如以前一样定义 bean,但是从容器中获得的其实是代理对象。3,配置 <aop:config>。4,配置 <aop:aspectj-autoproxy>,使用 AspectJ 的注解来表示之前以及切入点。而编程方式是直接通过 ProxyFactory 设置 target 对象,再通过 getProxy 方法来获取代理对象。 

         总的来说,在Spring AOP中,对于AOP的使用者来说,可能简单配置 Bean 即可,但仔细分析 Spring AOP 的内部设计就可以看到,为了让AOP起作用,需要参照前面的 AOP 实现原理来完成一系列过程,需要为目标对象建立代理对象,这个代理对象可以通过使用JDK的Proxy来完成,也可以通过第三方的类生成器CGLIB来完成。然后,还需要启动代理对象的拦截器来完成各种横切面的织入,这一系列的织入设计时通过一系列 Adapter 来实现的。通过一系列 Adapter 的设计,就可以把AOP的横切面设计和Proxy模式有机地结合起来,从而实现在 AOP 中定义各种织入方式(这里的源码部分可能不会涉及)。具体实现过程笔者会在后面的文章中详细阐述。


——水门(2016年3月于杭州

未经允许不得转载:SEARU.ORG » Spring 源码分析(三) —— AOP(一)AOP原理

赞 (0)
分享到:更多 ()

评论 0