aop_aop原理 - CSDN
aop 订阅
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。 展开全文
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
信息
衍生范型
函数式编程
又    意
葡萄酒
简    称
AOP
中文名
面向切面编程
属    性
软件开发技术
外文名
Aspect Oriented Programming
AOP名称含义
Aspect Oriented Programming(AOP)是较为热门的一个话题。AOP,国内大致译作“面向切面编程”。“面向切面编程”,这样的名字并不是非常容易理解,且容易产生一些误导。有些人认为“OOP/OOD11即将落伍,AOP是新一代软件开发方式”。显然,发言者并没有理解AOP的含义。Aspect,的确是“方面”的意思。不过,汉语传统语义中的“方面”,大多数情况下指的是一件事情的不同维度、或者说不同角度上的特性,比如我们常说:“这件事情要从几个方面来看待”,往往意思是:需要从不同的角度来看待同一个事物。这里的“方面”,指的是事物的外在特性在不同观察角度下的体现。而在AOP中,Aspect的含义,可能更多的理解为“切面”比较合适。可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,提高代码的灵活性和可扩展性,AOP可以说也是这种目标的一种实现。在Spring中提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。日志记录,性能统计,安全控制,事务处理,异常处理等等。将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
收起全文
精华内容
参与话题
  • AOP(Aspect Oriented Programming),意思是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

            经过我们对Spring的IOC不断的深入学习,Spring的面貌逐渐变得清晰,我们对Spring的了解也更加的深入。从这篇博文开始我们学习Spring的第二大核心内容:AOP。


    什么是AOP


            AOP(Aspect Oriented Programming),意思是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP基于IoC基础,是对OOP(Object Oriented Programming,面向对象)的延续。同时,AOP实际是GOF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,提高代码的灵活性和可扩展性,AOP可以说也是这种目标的一种实现。

           AOP将应用系统分为两部分,核心业务逻辑(Core business concerns)及横向的通用逻辑,也就是所谓的方面Crosscutting enterprise concerns,例如,所有大中型应用都要涉及到的持久化管理(Persistent)、事务管理(Transaction Management)、安全管理(Security)、日志管理(Logging)和调试管理(Debugging)等。


                       

    AOP与OOP的区别


            AOP、OOP在字面上虽然非常类似,但却是面向不同领域的两种设计思想。OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。

            而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异。

            上面的陈述可能过于理论化,举个简单的例子,对于“雇员”这样一个业务实体进行封装,自然是OOP/OOD的任务,我们可以为其建立一个“Employee”类,并将“雇员”相关的属性和行为封装其中。而用AOP设计思想对“雇员”进行封装将无从谈起。

            同样,对于“权限检查”这一动作片断进行划分,则是AOP的目标领域。而通过OOD/OOP对一个动作进行封装,则有点不伦不类。

           换而言之,OOD/OOP面向名词领域,AOP面向动词领域。


    基本概念


               要想真正的了解AOP,首先要了解几个重要的基本概念:

    1、切面(Aspect):对横切性关注点的模块化,其实就是共有功能的实现。如日志切面、权限切面等。

    2、连接点(JoinPoint):就是程序在运行过程中能够插入切面的地点。例如,方法调用、异常抛出或字段修改等,但Spring只支持

    方法级的连接点。

    3、通知(Advice):在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包

    括"around"、"before”和"after"等通知。许多AOP框架,包括Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截

    器链。

    4、切入点(Pointcut):用于定义通知(Advice)应该切入到哪些连接点(JoinPoint)上。不同的通知通常需要切入到不同的连接点上,这种精准的匹配是由切入点的正则表达式来定义的。

    5、目标对象(Target):就是那些即将切入切面的对象,也就是那些被通知的对象。

    6、代理对象(Proxy):将通知应用到目标对象之后被动态创建的对象。可以简单地理解为,代理对象的功能等于目标对象的核心

    业务逻辑功能加上共有功能。代理对象对于使用者而言是透明的,是程序运行过程中的产物。

    7、织入(Weaving):将切面应用到目标对象从而创建一个新的代理对象的过程。这个过程可以发生在编译期、类装载期及运行

    期,当然不同的发生点有着不同的前提条件。譬如发生在编译期的话,就要求有一个支持这种AOP实现的特殊编译器;发生在类装

    载期,就要求有一个支持AOP实现的特殊类装载器;只有发生在运行期,则可直接通过Java语言的反射机制与动态代理机制来动态

    实现。

          我们用一张图将这些概念串联起来,具体的代码在后面的博文中:



    通知(Advice)类型


           为了符合现实的各种需求,通知类型提供了5种,可以对目标方法进行全方位处理;

    1、Before advice:在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。

          ApplicationContext中在<aop:aspect>里面使用<aop:before>元素进行声明。

    2、After advice:当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

          ApplicationContext中在<aop:aspect>里面使用<aop:after>元素进行声明。

    3、After returnadvice:在某连接点正常完成后执行的通知,不包括抛出异常的情况。

          ApplicationContext中在<aop:aspect>里面使用<aop:after-returning>元素进行声明。

    4、Around advice:包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的

    行为,也可以选择不执行。

          ApplicationContext中在<aop:aspect>里面使用<aop:around>元素进行声明。

    5、Afterthrowing advice:在方法抛出异常退出时执行的通知。

          ApplicationContext中在<aop:aspect>里面使用<aop:after-throwing>元素进行声明。


    AOP 2种代理的区别


    AOP支持2种代理,Jdk的动态代理和CGLIB实现机制。二者有什么区别呢:

    Jdk基于接口实现:JDK动态代理对实现了接口的类进行代理。

    CGLIB基于继承:CGLIB代理可以对类代理,主要对指定的类生成一个子类,因为是继承,所以目标类最好不要使用final声明。 

    通常情况下,鼓励使用jdk代理,因为业务一般都会抽象出一个接口,而且不用引入新的东西。如果是遗留的系统,以前没有实现接口,那么只能使用CGLIB。


    AOP配置


    Spring AOP配置有两种风格:

          XML风格 = 采用声明形式实现Spring AOP 

          AspectJ风格 = 采用注解形式实现Spring AOP


         下篇博文,会分别使用两种风格实践一下Spring AOP,敬请关注。



    展开全文
  • AOP简介与作用

    万次阅读 多人点赞 2016-06-18 15:14:06
    AOPAspect Oriented Programming(AOP)是较为热门的一个话题。AOP,国内大致译作“面向切面编程”。 “面向切面编程”,这样的名字并不是非常容易理解,且容易产生一些误导。 笔者不止一次听到类似“OOP/OOD11即将...

    AOP

    Aspect Oriented Programming(AOP)是较为热门的一个话题。AOP,国内大致译作“面向切面编程”。

    • “面向切面编程”,这样的名字并不是非常容易理解,且容易产生一些误导。
    • 笔者不止一次听到类似“OOP/OOD11即将落伍,AOP是新一代软件开发方式”这样的发言。而在AOP中,Aspect的含义,可能更多的理解为“切面”比较合适。所以笔者更倾向于“面向切面编程”的译法。可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。
    • AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,提高代码的灵活性和可扩展性,AOP可以说也是这种目标的一种实现。
      应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。

    AOP主要功能

    日志记录,性能统计,安全控制,事务处理,异常处理等等wn及扩展

    AOP主要意图

    将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。arkdown Extra** 定义列表语法:

    代码块

    假设在一个应用系统中,有一个共享的数据必须被并发同时访问,首先,将这个数据封装在数据对象中,称为Data Class,同时,将有多个访问类,专门用于在同一时刻访问这同一个数据对象。
    为了完成上述并发访问同一资源的功能,需要引入锁Lock的概念,也就是说,某个时刻,当有一个访问类访问这个数据对象时,这个数据对象必须上锁Locked,用完后就立即解锁unLocked,再供其它访问类访问。
    使用传统的编程习惯,我们会创建一个抽象类,所有的访问类继承这个抽象父类,如下:
    abstract class Worker {
    abstract void locked();
    abstract void accessDataObject();
    abstract void unlocked();
    }
    accessDataObject()方法需要有“锁”状态之类的相关代码。

    Java只提供了单继承,因此具体访问类只能继承这个父类,如果具体访问类还要继承其它父类,比如另外一个如Worker的父类,将无法方便实现。

    重用被打折扣,具体访问类因为也包含“锁”状态之类的相关代码,只能被重用在相关有“锁”的场合,重用范围很窄。

    仔细研究这个应用的“锁”,它其实有下列特性:
    “锁”功能不是具体访问类的首要或主要功能,访问类主要功能是访问数据对象,例如读取数据或更改动作。
    “锁”

    这里写图片描述

    “锁”功能其实是这个系统的一个纵向切面,涉及许多类、许多类的方法。如上图:

    因此,一个新的程序结构应该是关注系统的纵向切面,例如这个应用的“锁”功能,这个新的程序结构就是aspect(方面)
    在这个应用中,“锁”方面(aspect)应该有以下职责:
    

    提供一些必备的功能,对被访问对象实现加锁或解锁功能。以保证所有在修改数据对象的操作之前能够调用lock()加锁,在它使用完成后,调用unlock()解锁。

    AOP应用范围

    很明显,AOP非常适合开发J2EE容器服务器,JBoss 4.0正是使用AOP框架进行开发。
    具体功能如下:
    Authentication 权限
    Caching缓存
    Context passing内容传递
    Error handling 错误处理
    Lazy loading 延时加载
    Debugging 调试
    logging, tracing, profiling and monitoring 记录跟踪 优化 校准
    Performance optimization性能优化
    Persistence 持久化
    Resource pooling资源池
    Synchronization 同步
    Transactions事务
    【AOP有必要吗?】

              当然,上述应用范例在没有使用AOP情况下,也得到了解决,例如JBoss 3.XXX也提供了上述应用功能,并且没有使用AOP。
    
              但是,使用AOP可以让我们从一个更高的抽象概念来理解软件系统,AOP也许提供一种有价值的工具。可以这么说:因为使用AOP结构,JBoss 4.0的源码要比JBoss 3.X容易理解多了,这对于一个大型复杂系统来说是非常重要的。
    
               从另外一个方面说,好像不是所有的人都需要关心AOP,它可能是一种架构设计的选择,如果选择J2EE系统,AOP关注的上述通用方面都已经被J2EE容器实现了,J2EE应用系统开发者可能需要更多地关注行业应用方面aspect。
    
               传统的程序通常表现出一些不能自然地适合单一的程序模块或者是几个紧密相关的程序模块的行为,AOP 将这种行为称为横切,它们跨越了给定编程模型中的典型职责界限。横切行为的实现都是分散的,软件设计师会发现这种行为难以用正常的逻辑来思考、实现和更改。最常见的一些横切行为如下面这些:
    

    1、日志记录,跟踪,优化和监控
    2、事务的处理
    3、持久化
    4、性能的优化
    5、资源池,如数据库连接池的管理
    6、系统统一的认证、权限管理等
    7、应用系统的异常捕捉及处理
    8、针对具体行业应用的横切行为

                前面几种横切行为都已经得到了密切的关注,也出现了各种有价值的应用,但也许今后几年,AOP 对针对具体行业应用的贡献会成为令人关注的焦点。
    

    AOP实现项目

    AOP是一个概念,并没有设定具体语言的实现,它能克服那些只有单继承特性语言的缺点(如Java),AOP具体实现有以下几个项目:

    →AspectJ (TM): 创建于Xerox PARC. 有近十年历史,成熟;
    →缺点:过于复杂;破坏封装;需要专门的Java编译器;
    →动态AOP:使用JDK的动态代理API或字节码Bytecode处理技术;
    →基于动态代理API的具体项目有:
    JBoss 4.0 JBoss 4.0服务器;
    →基于字节码的项目有:
    aspectwerkz ,spring。

    AOP作用

             面向过程编程离我们已经有些遥远,面向对象编程正主宰着软件世界。当每个新的软件设计师都被要求掌握如何将需求功能转化成一个个类,并且定义它们的数据成员、行为,以及它们之间复杂的关系的时候,面向切面编程(Aspect-Oriented Programming,AOP)为我们带来了新的想法、新的思想、新的模式。
    
             如果说面向对象编程是关注将需求功能划分为不同的并且相对独立,封装良好的类,并让它们有着属于自己的行为,依靠继承和多态等来定义彼此的关系的话;那么面向切面编程则是希望能够将通用需求功能从不相关的类当中分离出来,能够使得很多类共享一个行为,一旦发生变化,不必修改很多类,而只需要修改这个行为即可。
    
             面向切面编程是一个令人兴奋不已的新模式。就开发软件系统而言,它的影响力必将会和有着数十年应用历史的面向对象编程一样巨大。面向切面编程和面向对象编程不但不是互相竞争的技术而且彼此还是很好的互补。面向对象编程主要用于为同一对象层次的公用行为建模。
    
             它的弱点是将公共行为应用于多个无关对象模型之间。而这恰恰是面向切面编程适合的地方。有了 AOP,我们可以定义交叉的关系,并将这些关系应用于跨模块的、彼此不同的对象模型。AOP 同时还可以让我们层次化功能性而不是嵌入功能性,从而使得代码有更好的可读性和易于维护。它会和面向对象编程合作得很好。
    

    在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
    这里写图片描述
    1、面向切面编程(AOP)
      面向切面编程(AOP)就是对软件系统不同关注点的分离,开发者通过拦截方法调用并在方法调用前后添加辅助代码。
      AOP利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多了类的公共行为封装到一个可重用的模块,并将其命名为“Aspect”,即切面。
    这里写图片描述
      所谓“切面”,简单地说,就是将那些于业务无关,却为月舞模块所共同调用的逻辑或责任封装起来。
      ①切面就是横切面,代表的是一个普遍存在的共有功能。
      ②AOP代表的是一个横向关系
      ③AOP吧软件系统分为两个部分:核心关注点和横切关注点。
      ④业务出路的主要流程是核心关注点,与之关系不大的部分是横切关注点。
      横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。
    2、AOP的作用在与分离系统中各个关注点,将核心关注点和横切关注点分离开来。
    java代码:
    public class BusinessLogic{
      public voidSomeOPration(){
        //日志记录;
        //权限验证;
        DoSomething();
        //失误控制;
      }
    }
    3、AOP技术的实现
    AOP技术是建立在JAVA语言的反射机制与动态代理机制之上的。

    业务逻辑组件在运行过程中,AOP容器动态创建一个代理对象供使用者调用。该代理对象已经按程序员的意图将切面成功切入到目标方法的连接点上,从而切面的功能与业务逻辑的功能同时的以执行。

    AOP是一种编程概念,因此他并未绑定带任何特定的语言。事实上,他对所有单独的、垂直的分解式(AOP通常被认为是横向分解)的语言(不仅是OO语言)都有帮助。AOP在不同语言都有实现(如C++,Smalltalk,C#,C,Java)。
    4、拦截器的设计原理
      Struts2.0的拦截器的设计体现了一种编程的设计理念,即面向切面编程AOP。
      拦截是AOP的一种实现策略,在AOP中某个方法或字段被访问,可以进行拦截,然后在其之前或其之后加入某些操作。
    5、什么是拦截器(Interceptor)?
      拦截器是动态拦截Action调用的对象。他提供了中机制是开发者可以在一个Action执行之前或执行之后插入需要的代码。
    6、理解DRY(Don’t Repeat Yourself)规则
      在软件开发领域,有一个非常重要的规则:Don’t Repeat Yourself,就是所谓的DRY规则,意思就是不要写重复代码。
    这里写图片描述
    这里写图片描述
    为什么要使用方法调用呢?而不是在三个地方使用重复的代码呢?
      很多初学者认为是为了编程的简单,代码简洁。实际上,这是次要的,最重要的原因是为了软件后期的升级及维护。
      
    7、拦截器的意义
      拦截器是对调用方法的改进。我们说某个实例是一个拦截器时,这是从行为上来说的,如果从代码的角度来看,拦截器也是一个类,类中包含有方法,知识这个方法比较特殊,他会在目标方法调用之前“自动”执行。
      进一步改进,如下:
    作用: (1)提供可更高层次的解耦
         (2)允许改变被调用方法的方法体
           (3)可以改变调用的目标方法
        
    8、实现原理
      如何自动的调用拦截器,而且知道到底调用呢个拦截器的方法?大部分的时候,拦截器方法都是通过JDK的动态代理来调用的,AOP的实现机制。
      
    9、拦截器在Struts2.0中的角色
    作用:(1)拦截器是通过struts.xml文件配置的,从而实现了对Action通用操作的可插拨式管理。
      (2)降低了Action与特定代码的耦合性
      (3)提高了ACtion的复用性
      (4)吧多个Action中需要重复指定的代码取出,放在拦截器类中定义,从而提供更好地代码重用。
    10、Struts2中的拦截器
      在Struts2中已经在struts-default.xml中预定义了一些自带的拦截器,如timer、params等。
      如果在struts.xml中配置标签中继承struts-default,则当前package就会自动拥有struts-default.xml中的所有配置。代码如下:
      
    <package name="xxx" extends="struts-default" > ... </package>
    11、拦截器的定义
      在struts.xml文件中定义拦截器语法格式:
      <interceptor name="拦截器名" class=“拦截器实现类/”>
    12、应用定义好的拦截器
      <interceptor-ref name="拦截器名/">
    在struts-default.xml中有一个默认的引用,在默认情况下(也就是未引用拦截器时)会自动引用一些拦截器。
      <default-interceptor-ref name="defaultStack/">
    上面在defaultStack中引用的拦截器都可以不经过引用可以使用
    注意:如果在引用了任何拦截器后,要使用在defaultStack中定义的拦截器,需要重新引用。
    13、params拦截器使用
      当客户端的一个form想服务器端提交请求时,如有textfield,代码如下:
    这里写图片描述
    这里写图片描述
    在提交后,Struts2将会自动调用login动作类中的setXX方法,并将文本框中的值通过setXXX方法的参数传入。
    实际上,这个操作是由params拦截器完成的,params对应的类是com.opensymphony.xwork2.interception.Parameterslnterceptor.
    由于params已经在defaultStack中定义,因此,在未引用拦截器的是会自动引用params的。
    如下面的配置代码,在访问login动作时,Struts是会自动执行相应的setter方法的。
    这里写图片描述
    这样,登陆表单中的用户名,密码参数就会在Action类中被set进去,完成登陆功能。
    但如果在action中引用了其他拦截器,就必须显示的引用params拦截器,Struts2不能调用相应的setter方法来初始化参数。如下面的配置代码所示:
    这里写图片描述
    这里写图片描述
    我们可以不去配置params拦截器,配置timer和logger或任意一个,测试参数username、password的值,应该是没有得到表单提交的值,因为params拦截器已经不起作用了。
    14、使用拦截器栈
    为了能在多个动作中方便的引用同一个或几个拦截器,可以使用拦截器栈将这些拦截器当个整体来引用。
    拦截器栈要在 package 标签中使用 interceptors 和子标签interceptor-stack来定可以像使用拦截器一样使用拦截器栈。
    这里写图片描述
    这里写图片描述

    展开全文
  • Spring AOP详细介绍

    万次阅读 多人点赞 2019-04-14 21:32:57
    什么是AOP AOP(Aspect-OrientedProgramming,面向切面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共...

    什么是AOP

            AOP(Aspect-OrientedProgramming,面向切面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

           而AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。

    一 AOP的基本概念

    • (1)Aspect(切面):通常是一个类,里面可以定义切入点和通知
    • (2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用
    • (3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around
    • (4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式
    • (5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

    通知方法:

    1. 前置通知:在我们执行目标方法之前运行(@Before)
    2. 后置通知:在我们目标方法运行结束之后 ,不管有没有异常(@After)
    3. 返回通知:在我们的目标方法正常返回值后运行(@AfterReturning)
    4. 异常通知:在我们的目标方法出现异常后运行(@AfterThrowing)
    5. 环绕通知:动态代理, 需要手动执行joinPoint.procced()(其实就是执行我们的目标方法执行之前相当于前置通知, 执行之后就相当于我们后置通知(@Around)

    二 Spring AOP

           Spring中的AOP代理还是离不开Spring的IOC容器,代理的生成,管理及其依赖关系都是由IOC容器负责,Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理,不过现在的项目都是面向接口编程,所以JDK动态代理相对来说用的还是多一些。

    三 基于注解的AOP配置方式

    切面类:

    package com.enjoy.cap10.aop;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    
    //日志切面类
    @Aspect
    public class LogAspects {
    	@Pointcut("execution(public int com.enjoy.cap10.aop.Calculator.*(..))")
    	public void pointCut(){};
    	
    	//@before代表在目标方法执行前切入, 并指定在哪个方法前切入
    	@Before("pointCut()")
    	public void logStart(){
    		System.out.println("除法运行....参数列表是:{}");
    	}
    	@After("pointCut()")
    	public void logEnd(){
    		System.out.println("除法结束......");
    	}
    	@AfterReturning("pointCut()")
    	public void logReturn(){
    		System.out.println("除法正常返回......运行结果是:{}");
    	}
    	@AfterThrowing("pointCut()")
    	public void logException(){
    		System.out.println("运行异常......异常信息是:{}");
    	}
    	@Around("pointCut()")
    	public Object Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
    		System.out.println("@Arount:执行目标方法之前...");
    		Object obj = proceedingJoinPoint.proceed();//相当于开始调div地
    		System.out.println("@Arount:执行目标方法之后...");
    		return obj;
    	}
    }

    目标方法:

    package com.enjoy.cap10.aop;
    
    public class Calculator {
    	//业务逻辑方法
    	public int div(int i, int j){
    		System.out.println("--------");
    		return i/j;
    	}
    }

    配置类:

    package com.enjoy.cap10.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    
    import com.enjoy.cap10.aop.Calculator;
    import com.enjoy.cap10.aop.LogAspects;
    
    @Configuration
    @EnableAspectJAutoProxy
    public class Cap10MainConfig {
    	@Bean
    	public Calculator calculator(){
    		return new Calculator();
    	}
    
    	@Bean
    	public LogAspects logAspects(){
    		return new LogAspects();
    	}
    }

    测试类:

    public class Cap10Test {
    	@Test
    	public void test01(){
    		AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap10MainConfig.class);	
    		Calculator c = app.getBean(Calculator.class);
    		int result = c.div(4, 3);
    		System.out.println(result);
    		app.close();
    
    	}
    }

    结果:

    @Arount:执行目标方法之前...
    除法运行....参数列表是:{}
    --------
    @Arount:执行目标方法之后...
    除法结束......
    除法正常返回......运行结果是:{}
    1

    AOP源码赏析

    在这个注解比较流行的年代里,当我们想要使用spring 的某些功能时只需要加上一行代码就可以了,比如:

    • @EnableAspectJAutoProxy开启AOP
    • @EnableTransactionManagement开启spring事务管理,
    • @EnableCaching开启spring缓存
    • @EnableWebMvc 开启webMvc

            对于我们使用者而言十分简单便利,然而,其背后所做的事,却远远比一个注解复杂的多了,本篇只是简略的介绍一下@EnableAspectJAutoProxy背后所发生的那些事,了解其工作原理,才能更好的运用,并从中领略大师的智慧.

    废话不多说,先来看一下源码:

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(AspectJAutoProxyRegistrar.class)
    public @interface EnableAspectJAutoProxy {
    
        /**
         * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
         * to standard Java interface-based proxies. The default is {@code false}.
         */
        boolean proxyTargetClass() default false;
    
        /**
         * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
         * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
         * Off by default, i.e. no guarantees that {@code AopContext} access will work.
         * @since 4.3.1
         */
        boolean exposeProxy() default false;
    
    }

           英文注解已经很详细了,这里简单介绍一下两个参数,一个是控制aop的具体实现方式,为true 的话使用cglib,为false的话使用java的Proxy,默认为false,第二个参数控制代理的暴露方式,解决内部调用不能使用代理的场景,默认为false.

    这里核心是@Import(AspectJAutoProxyRegistrar.class);在AspectJAutoProxyRegistrar里,核心的地方是

    AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

           一个AOP的工具类,这个工具类的主要作用是把AnnotationAwareAspectJAutoProxyCreator这个类定义为BeanDefinition放到spring容器中,这是通过实现ImportBeanDefinitionRegistrar接口来装载的,具体装载过程不是本篇的重点,这里就不赘述,我们重点看AnnotationAwareAspectJAutoProxyCreator这个类.

    首先看看这个类图:

            从类图是可以大致了解AnnotationAwareAspectJAutoProxyCreator这个类的功能.它实现了一系列Aware的接口,在Bean装载的时候获取BeanFactory(Bean容器),Bean的ClassLoader,还实现了order接口,继承了PorxyConfig,ProxyConfig中主要封装了代理的通用处理逻辑,比如设置目标类,设置使用cglib还是java proxy等一些基础配置.

           而能够让这个类参与到bean初始化功能,并为bean添加代理功能的还是因为它实现了BeanPostProcessor这个接口.这个接口的postProcessAfterInitialization方法会在bean初始化结束后(赋值完成)被调用

    这里先看一下最顶部的抽象类:AbstractAutoProxyCreator,这个抽象类主要抽象了实现代理的逻辑:

    @Override
    	public Object postProcessBeforeInitialization(Object bean, String beanName) {
    		return bean;
    	}
     
        // 主要看这个方法,在bean初始化之后对生产出的bean进行包装
    	@Override
    	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		if (bean != null) {
    			Object cacheKey = getCacheKey(bean.getClass(), beanName);
    			if (!this.earlyProxyReferences.contains(cacheKey)) {
    				return wrapIfNecessary(bean, beanName, cacheKey);
    			}
    		}
    		return bean;
    	}
     
        // wrapIfNecessary
    	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    		if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
    			return bean;
    		}
    		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
    			return bean;
    		}
    		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    			this.advisedBeans.put(cacheKey, Boolean.FALSE);
    			return bean;
    		}
     
    		// Create proxy if we have advice.
            // 意思就是如果该类有advice则创建proxy,
    		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    		if (specificInterceptors != DO_NOT_PROXY) {
    			this.advisedBeans.put(cacheKey, Boolean.TRUE);
                // 1.通过方法名也能简单猜测到,这个方法就是把bean包装为proxy的主要方法,
    			Object proxy = createProxy(
    					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    			this.proxyTypes.put(cacheKey, proxy.getClass());
                
                // 2.返回该proxy代替原来的bean
    			return proxy;
    		}
     
    		this.advisedBeans.put(cacheKey, Boolean.FALSE);
    		return bean;
    	}
    

     总结:

    • 1)将AnnotationAwareAspectJAutoProxyCreator注册到Spring容器中
    • 2)AnnotationAwareAspectJAutoProxyCreator类的postProcessAfterInitialization()方法将所有有advice的bean重新包装成proxy
       

    创建proxy过程分析

            通过之前的代码结构分析,我们知道,所有的bean在返回给用户使用之前都需要经过AnnotationAwareAspectJAutoProxyCreator类的postProcessAfterInitialization()方法,而该方法的主要作用也就是将所有拥有advice的bean重新包装为proxy,那么我们接下来直接分析这个包装为proxy的方法即可,看一下bean如何被包装为proxy,proxy在被调用方法时,是具体如何执行的

     以下是AbstractAutoProxyCreator.wrapIfNecessary(Object bean, String beanName, Object cacheKey)中的createProxy()代码片段分析

    protected Object createProxy(
    			Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
     
    		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
    			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    		}
     
            // 1.创建proxyFactory,proxy的生产主要就是在proxyFactory做的
    		ProxyFactory proxyFactory = new ProxyFactory();
    		proxyFactory.copyFrom(this);
     
    		if (!proxyFactory.isProxyTargetClass()) {
    			if (shouldProxyTargetClass(beanClass, beanName)) {
    				proxyFactory.setProxyTargetClass(true);
    			}
    			else {
    				evaluateProxyInterfaces(beanClass, proxyFactory);
    			}
    		}
     
            // 2.将当前bean适合的advice,重新封装下,封装为Advisor类,然后添加到ProxyFactory中
    		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    		for (Advisor advisor : advisors) {
    			proxyFactory.addAdvisor(advisor);
    		}
     
    		proxyFactory.setTargetSource(targetSource);
    		customizeProxyFactory(proxyFactory);
     
    		proxyFactory.setFrozen(this.freezeProxy);
    		if (advisorsPreFiltered()) {
    			proxyFactory.setPreFiltered(true);
    		}
     
            // 3.调用getProxy获取bean对应的proxy
    		return proxyFactory.getProxy(getProxyClassLoader());
    	}

            TargetSource中存放被代理的对象,这段代码主要是为了构建ProxyFactory,将配置信息(是否使用java proxy,是否threadlocal等),目标类,切面,传入ProxyFactory中

    1)创建何种类型的Proxy?JDKProxy还是CGLIBProxy?

    // getProxy()方法
    	public Object getProxy(ClassLoader classLoader) {
    		return createAopProxy().getProxy(classLoader);
    	}
     
        
        // createAopProxy()方法就是决定究竟创建何种类型的proxy
    	protected final synchronized AopProxy createAopProxy() {
    		if (!this.active) {
    			activate();
    		}
            // 关键方法createAopProxy()
    		return getAopProxyFactory().createAopProxy(this);
    	}
     
        // createAopProxy()
    	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
            // 1.config.isOptimize()是否使用优化的代理策略,目前使用与CGLIB
            // config.isProxyTargetClass() 是否目标类本身被代理而不是目标类的接口
            // hasNoUserSuppliedProxyInterfaces()是否存在代理接口
    		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
    			Class<?> targetClass = config.getTargetClass();
    			if (targetClass == null) {
    				throw new AopConfigException("TargetSource cannot determine target class: " +
    						"Either an interface or a target is required for proxy creation.");
    			}
                
                // 2.如果目标类是接口或者是代理类,则直接使用JDKproxy
    			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
    				return new JdkDynamicAopProxy(config);
    			}
                
                // 3.其他情况则使用CGLIBproxy
    			return new ObjenesisCglibAopProxy(config);
    		}
    		else {
    			return new JdkDynamicAopProxy(config);
    		}
    	}

    2)getProxy()方法

    由1)可知,通过createAopProxy()方法来确定具体使用何种类型的Proxy,针对于该示例,我们具体使用的为JdkDynamicAopProxy,下面来看下JdkDynamicAopProxy.getProxy()方法

    final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable// JdkDynamicAopProxy类结构,由此可知,其实现了InvocationHandler,则必定有invoke方法,来被调用,也就是用户调用bean相关方法时,此invoke()被真正调用
        // getProxy()
        public Object getProxy(ClassLoader classLoader) {
    		if (logger.isDebugEnabled()) {
    			logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
    		}
    		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
            
            // JDK proxy 动态代理的标准用法
    		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    	}

    3)invoke()方法

        以上的代码模式可以很明确的看出来,使用了JDK动态代理模式,真正的方法执行在invoke()方法里,下面我们来看下该方法,来看下bean方法如何被代理执行的

    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		MethodInvocation invocation;
    		Object oldProxy = null;
    		boolean setProxyContext = false;
     
    		TargetSource targetSource = this.advised.targetSource;
    		Class<?> targetClass = null;
    		Object target = null;
     
    		try {
                // 1.以下的几个判断,主要是为了判断method是否为equals、hashCode等Object的方法
    			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
    				// The target does not implement the equals(Object) method itself.
    				return equals(args[0]);
    			}
    			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
    				// The target does not implement the hashCode() method itself.
    				return hashCode();
    			}
    			else if (method.getDeclaringClass() == DecoratingProxy.class) {
    				// There is only getDecoratedClass() declared -> dispatch to proxy config.
    				return AopProxyUtils.ultimateTargetClass(this.advised);
    			}
    			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
    					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
    				// Service invocations on ProxyConfig with the proxy config...
    				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
    			}
     
    			Object retVal;
     
    			if (this.advised.exposeProxy) {
    				// Make invocation available if necessary.
    				oldProxy = AopContext.setCurrentProxy(proxy);
    				setProxyContext = true;
    			}
     
    			// May be null. Get as late as possible to minimize the time we "own" the target,
    			// in case it comes from a pool.
    			target = targetSource.getTarget();
    			if (target != null) {
    				targetClass = target.getClass();
    			}
     
    			// 2.获取当前bean被拦截方法链表
    			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
     
    			// 3.如果为空,则直接调用target的method
    			if (chain.isEmpty()) {
    				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
    				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
    			}
                // 4.不为空,则逐一调用chain中的每一个拦截方法的proceed
    			else {
    				// We need to create a method invocation...
    				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
    				// Proceed to the joinpoint through the interceptor chain.
    				retVal = invocation.proceed();
    			}
     
    			...
    			return retVal;
    		}
    		...
    	}

    4)拦截方法真正被执行调用invocation.proceed() 

    	public Object proceed() throws Throwable {
    		//	We start with an index of -1 and increment early.
    		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
    			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.
    			InterceptorAndDynamicMethodMatcher dm =
    					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
    			if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
    				return dm.interceptor.invoke(this);
    			}
    			else {
    				// Dynamic matching failed.
    				// Skip this interceptor and invoke the next in the chain.
    				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(this);
    		}
    	}

     总结4:依次遍历拦截器链的每个元素,然后调用其实现,将真正调用工作委托给各个增强器

    总结:

        纵观以上过程可知:实际就是为bean创建一个proxy,JDKproxy或者CGLIBproxy,然后在调用bean的方法时,会通过proxy来调用bean方法

        重点过程可分为:

        1)将AnnotationAwareAspectJAutoProxyCreator注册到Spring容器中

        2)AnnotationAwareAspectJAutoProxyCreator类的postProcessAfterInitialization()方法将所有有advice的bean重新包装成proxy

        3)调用bean方法时通过proxy来调用,proxy依次调用增强器的相关方法,来实现方法切

    转载:https://blog.csdn.net/qq_26323323/article/details/81012855

    展开全文
  • 细说Spring——AOP详解(AOP概览)

    万次阅读 多人点赞 2018-05-30 18:29:25
    一、对AOP的初印象 首先先给出一段比较专业的术语(来自百度): 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方 式和运行期动态代理实现程序功能的统一维护的一种技术。...

    一、对AOP的初印象

    首先先给出一段比较专业的术语(来自百度):

    在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方
    式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个
    热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑
    的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高
    了开发的效率。
    

    然后我们举一个比较容易理解的例子(来自:Spring 之 AOP):

    要理解切面编程,就需要先理解什么是切面。用刀把一个西瓜分成两瓣,切开的切口就是切面;炒菜,锅与炉子共同来完成炒菜,锅与炉子就是切面。web层级设计中,web层->网关层->服务层->数据层,每一层之间也是一个切面。编程中,对象与对象之间,方法与方法之间,模块与模块之间都是一个个切面。

    我们一般做活动的时候,一般对每一个接口都会做活动的有效性校验(是否开始、是否结束等等)、以及这个接口是不是需要用户登录。

    按照正常的逻辑,我们可以这么做。
    这里写图片描述

    这有个问题就是,有多少接口,就要多少次代码copy。对于一个“懒人”,这是不可容忍的。好,提出一个公共方法,每个接口都来调用这个接口。这里有点切面的味道了。
    这里写图片描述

    同样有个问题,我虽然不用每次都copy代码了,但是,每个接口总得要调用这个方法吧。于是就有了切面的概念,我将方法注入到接口调用的某个地方(切点)。

    这里写图片描述

    这样接口只需要关心具体的业务,而不需要关注其他非该接口关注的逻辑或处理。
    红框处,就是面向切面编程。

    二、AOP中的相关概念

    看过了上面的例子,我想大家脑中对AOP已经有了一个大致的雏形,但是又对上面提到的切面之类的术语有一些模糊的地方,接下来就来讲解一下AOP中的相关概念,了解了AOP中的概念,才能真正的掌握AOP的精髓。
    这里还是先给出一个比较专业的概念定义

    • Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。
    • Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。
    • Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。
    • Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。
    • Target(目标对象):织入 Advice 的目标对象.。
    • Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程

    然后举一个容易理解的例子
    看完了上面的理论部分知识, 我相信还是会有不少朋友感觉到 AOP 的概念还是很模糊, 对 AOP 中的各种概念理解的还不是很透彻. 其实这很正常, 因为 AOP 中的概念是在是太多了, 我当时也是花了老大劲才梳理清楚的.
    下面我以一个简单的例子来比喻一下 AOP 中 Aspect, Joint point, PointcutAdvice之间的关系.
    让我们来假设一下, 从前有一个叫爪哇的小县城, 在一个月黑风高的晚上, 这个县城中发生了命案. 作案的凶手十分狡猾, 现场没有留下什么有价值的线索. 不过万幸的是, 刚从隔壁回来的老王恰好在这时候无意中发现了凶手行凶的过程, 但是由于天色已晚, 加上凶手蒙着面, 老王并没有看清凶手的面目, 只知道凶手是个男性, 身高约七尺五寸. 爪哇县的县令根据老王的描述, 对守门的士兵下命令说: 凡是发现有身高七尺五寸的男性, 都要抓过来审问. 士兵当然不敢违背县令的命令, 只好把进出城的所有符合条件的人都抓了起来.

    来让我们看一下上面的一个小故事和 AOP 到底有什么对应关系.
    首先我们知道, 在 Spring AOP 中 Joint point 指代的是所有方法的执行点, 而 point cut 是一个描述信息, 它修饰的是 Joint point, 通过 point cut, 我们就可以确定哪些 Joint point 可以被织入 Advice. 对应到我们在上面举的例子, 我们可以做一个简单的类比, Joint point 就相当于 爪哇的小县城里的百姓,pointcut 就相当于 老王所做的指控, 即凶手是个男性, 身高约七尺五寸, Advice 则是施加在符合老王所描述的嫌疑人的动作: 抓过来审问.
    为什么可以这样类比呢?

    • Joint point : 爪哇的小县城里的百姓: 因为根据定义, Joint point 是所有可能被织入 Advice 的候选的点, 在 Spring AOP中, 则可以认为所有方法执行点都是 Joint point. 而在我们上面的例子中, 命案发生在小县城中, 按理说在此县城中的所有人都有可能是嫌疑人.

    • Pointcut :男性, 身高约七尺五寸: 我们知道, 所有的方法(joint point) 都可以织入 Advice, 但是我们并不希望在所有方法上都织入 Advice, 而 Pointcut 的作用就是提供一组规则来匹配joinpoint, 给满足规则的 joinpoint 添加 Advice. 同理, 对于县令来说, 他再昏庸, 也知道不能把县城中的所有百姓都抓起来审问, 而是根据凶手是个男性, 身高约七尺五寸, 把符合条件的人抓起来. 在这里 凶手是个男性, 身高约七尺五寸 就是一个修饰谓语, 它限定了凶手的范围, 满足此修饰规则的百姓都是嫌疑人, 都需要抓起来审问.

    • Advice :抓过来审问, Advice 是一个动作, 即一段 Java 代码, 这段 Java 代码是作用于 point cut 所限定的那些 Joint point 上的. 同理, 对比到我们的例子中, 抓过来审问 这个动作就是对作用于那些满足 男性, 身高约七尺五寸 的爪哇的小县城里的百姓.

    • Aspect::Aspect 是 point cut 与 Advice 的组合, 因此在这里我们就可以类比: “根据老王的线索, 凡是发现有身高七尺五寸的男性, 都要抓过来审问” 这一整个动作可以被认为是一个 Aspect.

    最后是一个描述这些概念之间关系的图
    这里写图片描述

    三、其他的一些内容

    AOP中的Joinpoint可以有多种类型:构造方法调用,字段的设置和获取,方法的调用,方法的执行,异常的处理执行,类的初始化。也就是说在AOP的概念中我们可以在上面的这些Joinpoint上织入我们自定义的Advice,但是在Spring中却没有实现上面所有的joinpoint,确切的说,Spring只支持方法执行类型的Joinpoint

    Advice 的类型

    • before advice, 在 join point 前被执行的 advice. 虽然 before advice 是在 join point 前被执行, 但是它并不能够阻止 join point 的执行, 除非发生了异常(即我们在 before advice 代码中, 不能人为地决定是否继续执行 join point 中的代码)

    • after return advice, 在一个 join point 正常返回后执行的 advice

    • after throwing advice, 当一个 join point 抛出异常后执行的 advice
    • after(final) advice, 无论一个 join point 是正常退出还是发生了异常, 都会被执行的 advice.
    • around advice, 在 join point 前和 joint point 退出后都执行的 advice. 这个是最常用的 advice.
    • introduction,introduction可以为原有的对象增加新的属性和方法。

    Spring中,通过动态代理和动态字节码技术实现了AOP,这些内容,我们将在以后进行讲解。

    展开全文
  • 本文目标:带领大家阅读aop的源码,深入理解aop的原理,内容有点长,消化需要大概一周时间,做好准备。阅读本文之前,需要先掌握下面3篇文章内容,不然会比较吃力。Spring系列第15篇:...
  • AOP

    万次阅读 多人点赞 2019-04-10 14:07:17
    AOP(Aspect Oriented Programming),是面向切面编程的技术。AOP基于IOC基础,是对OOP的有益补充。 AOP将应用系统拆分为个部分:核心业务逻辑及横向的通用逻辑,也就是所谓的切面。 举例:所有大中型应用都要涉及到...
  • 简单描述下AOP

    千次阅读 2018-07-13 13:27:25
    什么是AOPAOP(Aspect-OrientedProgramming,面向切面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为...
  • AOP如何实现及实现原理

    万次阅读 多人点赞 2018-11-24 10:41:03
    最近在开发中遇到了一个刚好可以用AOP实现的例子,就顺便研究了AOP的实现原理,把学习到的东西进行一个总结。文章中用到的编程语言为kotlin,需要的可以在IDEA中直接转为java。 这篇文章将会按照如下目录展开: AOP...
  • AOP【面向切面编程】

    万次阅读 多人点赞 2019-05-25 21:27:30
    文章目录AOP介绍AOP术语AOP的实现方式 AOP介绍 AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming),面向对象编程的补充和完善。  面向切面编程是面向对象中的一种...
  • 实现AOP的几种方式

    万次阅读 2018-05-15 15:00:17
    AOP是一种编程思想,是OOP编程思想的补充。AOP的实现有很多种,下面简单介绍几种。 测试AOP需要的一些基础类 Font.java package com.java.proxy; import lombok.Data; @Data public class Font { private ...
  • 在Spring AOP切面中启用新事务

    万次阅读 多人点赞 2019-07-31 19:16:01
    sping的声明式事务就是靠AOP来实现的,一般事务都在业务层中启用,那如果要在AOP的逻辑中启用一个新的事务要怎么做呢?比如下面的例子: //定义一个切点,这里指com.lidehang.remote包下所有的类的方法...
  • Spring boot2 配置AOP日志

    万次阅读 2019-01-04 16:57:14
    Spring boot2 配置AOP前置增强,后置增强,异常增强,环绕增强,最终增强 关于AOP切面相关具体概念不做过多阐述(概念弄懂有利于理解思想),这是配置AOP的各种增强日志,解决日志嵌套在业务代码的麻烦和不科学 先来个Git ...
  • 关于 Spring AOP (AspectJ) 你该知晓的一切

    万次阅读 多人点赞 2017-02-21 08:00:47
    【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) ... 出自【zejian的博客】 关联文章: ...关于 Spring AOP (AspectJ) 你该知晓的一切本篇是年后第一篇博文,由于博主用了不少
  • AOP全称(Aspect Oriented Programming)面向切片编程的简称 AOP的定义: AOP通过预编译方式和运行期动态代理实现,在不修改源代码的情况下,给程序动态统一添加功能的一种技术,简称AOP。是spring框架的一个重要...
  • java技术——Spring Aop

    万次阅读 多人点赞 2016-04-21 21:58:57
    AOP(Aspect Orient Programming),也就是面向切面编程。可以这样理解,面向对象编程(OOP)是从静态角度考虑程序结构,面向切面编程(AOP)是从动态角度考虑程序运行过程。 AOP原理图 下面是一个spring ...
  • using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Castle.DynamicProxy; ...namespace Core.Util ... internal class CastleInterceptor : AsyncInterceptorBase...
  • J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP前言  搜狐畅游笔试题中有一道问答题涉及到回答谈谈对Spring IOC与AOP的理解。特将相关内容进行整理。  IOC和AOP是Spring中的两个核心的概念,下面...
  • 【SpringBoot】SpingBoot整合AOP

    万次阅读 多人点赞 2018-09-07 00:47:33
    说起spring,我们知道其最核心的两个功能就是AOP(面向切面)和IOC(控制反转),这边文章来总结一下SpringBoot如何整合使用AOP。 一、示例应用场景:对所有的web请求做切面来记录日志。 1、pom中引入SpringBoot的...
  • Spring AOP 实现原理

    万次阅读 多人点赞 2013-09-24 15:23:43
    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为...
  • SpringAOP详细配置与使用

    万次阅读 多人点赞 2018-06-11 00:16:18
    SpringAOP简介 AOP概念 Spring AOP简单流程图 Spring AOP之Annotation 前置通知(Before advice) 返回后通知(After reurning advice) 抛出异常后通知(After throwing advice) 后置通知(After (finally) advice...
1 2 3 4 5 ... 20
收藏数 329,997
精华内容 131,998
关键字:

aop