Spring(五)AOP

AOP概述

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

可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,提高代码的灵活性和可扩展性,AOP可以说也是这种目标的一种实现。

在Spring中提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。

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

AOP和OOP

AOP和OOP互为补充,面向对象编程将程序分解成各个层次的对象,而面向切面编程将程序运行过程分解成各个切面。可以简单地理解成:面向对象编程时从静态角度考虑程序结构,而面向切面编程则是从动态角度考虑程序运行过程。

OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。

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

例如:对于“雇员”这样一个业务实体进行封装,自然是OOP/OOD的任务,我们可以为其建立一个“Employee”类,并将“雇员”相关的属性和行为封装其中。而用AOP设计思想对“雇员”进行封装将无从谈起。同样,对于“权限检查”这一动作片断进行划分,则是AOP的目标领域。而通过OOD/OOP对一个动作进行封装,则有点不伦不类。可以认为,OOD/OOP面向名词领域,AOP面向动词领域。

传统的OOP编程里以对象为核心,整个软件系统由一系列相互依赖的对象组成,而这些对象将被抽象成一个个类,并允许通过类继承来管理类与类之间一般到特殊的关系。由于类可以继承,因此可以把具有相同功能或相同特性的属性抽象到一个层次分明的类结构体系中。OOP这种编程理念的提出本身是很强大的,其优势在业界是有目共睹的。但随着软件规模的增大,应用的不断升级优化,在应对某些场景需求方面,OOP也会显得不擅长。

比如说,越来越多的非业务需求(日志和验证等)加入后, 原有的业务方法急剧膨胀. 每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点,这会导致代码异常混乱。在日志需求方面, 为了满足这个单一需求, 就不得不在多个模块(方法)里多次重复相同的日志代码。如果日志需求发生变化, 必须修改所有模块,这会导致代码分散,不利于维护。

针对这样的一些问题 ,很多人会认为一个定义良好的 OOP 的接应该也能够解决。定义良好的 OOP 的接口的确可以解决这样的一些问题。但是,对于 OOP 中的接口来说,它仍然需要我们在相应的模块中去调用该接口中相关的方法,这是 OOP 所无法避免的,并且一旦接口不得不进行修改的时候,所有事情会变得一团糟。AOP 则不会这样,你只需要修改相应的 Aspect,再重新编织(weave)即可。但是AOP 也不能代替 OOP。核心的需求仍然会由 OOP 来加以实现,而 AOP 将会和 OOP 整合起来,互补长短。



开启AOP之旅

在应用 AOP 编程时, 仍然需要定义公共功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类. 这样一来横切关注点就被模块化到特殊的对象(切面)里。

AOP 的好处:

各步骤之间有良好的隔离性,每个事物逻辑位于一个位置, 代码不分散, 便于维护和升级。

源代码无关性。业务模块更简洁, 只包含核心业务代码。

AOP 术语

>切面(Aspect): 横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象。切面用于组织多个Advice,Advice放在切面中定义。

>增强处理(Advice): AOP框架在特定的切入点执行的增强处理。处理有“around”、“before”和“after”等类型。

>目标(Target): 被AOP框架进行增强处理的对象,也被称为被增强的对象。如果AOP框架采用的是动态AOP实现,该对象就是一个被代理的对象。

>代理(Proxy): AOP框架创建的对象,可以简单地理解成,代理就是对目标对象的增强的加强。Spring的AOP代理可以是JDK动态代理,也可以是cglib代理。前者为实现接口的目标对象的代理,后者为不实现接口的目标对象代理。

>连接点(Joinpoint):程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位。例如 ArithmethicCalculator#add() 方法执行前的连接点,执行点为 ArithmethicCalculator#add(); 方位为该方法执行前的位置

>切点(pointcut):可以插入增强处理的连接点。当某个连接点满足指定要求时。该连接点将添加增强处理,该连接点就变成切入点。每个类都拥有多个连接点:例如 ArithmethicCalculator 的所有方法实际上都是连接点,即连接点是程序类中客观存在的事务。AOP 通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过 org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。

>引入(Introduction):用来给一个类型声明额外的方法或属性(也被称为连接类型声明(inter-type declaration))。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用引入来使一个bean实现IsModified接口,以便简化缓存机制。

>织入(Weaving):把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。

通知类型

>前置通知(Before advice):在某连接点之前执行的通知,但这个通知不能阻止连接点之前的执行流程(除非它抛出一个异常)。

>后置通知(After returning advice):在某连接点正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。

>异常通知(After throwing advice):在方法抛出异常退出时执行的通知。

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

>环绕通知(Around Advice):包围一个连接点的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它自己的返回值或抛出异常来结束执行。

环绕通知是最常用的通知类型。和AspectJ一样,Spring提供所有类型的通知,我们推荐你使用尽可能简单的通知类型来实现需要的功能。例如,如果你只是需要一个方法的返回值来更新缓存,最好使用后置通知而不是环绕通知,尽管环绕通知也能完成同样的事情。用最合适的通知类型可以使得编程模型变得简单,并且能够避免很多潜在的错误。比如,你不需要在JoinPoint上调用用于环绕通知的proceed()方法,就不会有调用的问题。

使用AspectJ实现AOP

AspectJ是基于Java语言的AOP框架,提供了强大的AOP功能。Spring4.0的AOP与AspectJ进行了良好的集成。

AspectJ主要包括两部分:一个部分定义了如何表达、定义AOP编程中的语法规范;另一部分是工具部分,包括编译器、调试工具等。

>本地安装AspectJ

AspectJ是Eclipse下面的一个开源项目,下载地址:http://www.eclipse.org/aspectj/downloads.php,下载完成后得到一个aspectj-1.8.9.jar文件,打开命令行窗口,进入aspectj-1.8.9.jar文件所在路径,输入如下命令:

java -jar aspectj-1.8.9.jar

运行上面命令会跳出如下窗口,按提示选好安装路径,然后分别按提示添加CLASSPATH、PATH。

成功安装了Aspectj后,会在D:\developer\java\aspectj1.8路径下(Aspectj的安装路径)看到如下文件结构。

>bin路径下存放aj、aj5、ajc、ajdoc、ajbrowser等命令,其中ajc命令为常用命令,作用类似于9javac,用于对普通的java类进行编译时增强。

>doc路径下存放Aspectj的使用说明、参考手册、API文档等文档。

>lib路径下的4个jar包文件是Aspectj的核心类库。

>在eclipse里安装AspectJ

在eclipse里要使用AspectJ创建项目,要配置AspectJ插件AJDT 。首先,打开AJDT下载页: http://www.eclipse.org/ajdt/downloads/ ,看到如下页面。

找到对应eclipse版本的ajdt更新地址,将其复制到eclipse插件安装网址搜寻框。

点击”Next”下一步安装,安装完成后重启eclipse,点“New”新建项目,可以在新建对话框里看到Aspect项目相关选项。

这样就可在eclipse里创建AspectJ项目应用了。

>AspectJ应用示例

下面先写两个简单的Java类,用于模拟系统中的业务逻辑组件,实际应用好在哪个无论多少个类,AspectJ的处理方式都是一样的。

package com.afy.app.service;

public class Hello
{
    // 定义一个简单方法,模拟应用中的业务逻辑方法
    public void foo()
    {
        System.out.println("执行Hello组件的foo()方法");
    }
    // 定义一个addUser()方法,模拟应用中的添加用户的方法
    public int addUser(String name , String pass)
    {
        System.out.println("执行Hello组件的addUser添加用户:" + name);
        return 20;
    }
}

另外一个World组件类如下。

package com.afy.app.service;

public class World{
    // 定义一个简单方法,模拟应用中的业务逻辑方法
    public void bar(){
        System.out.println("执行World组件的bar()方法");
    }
}

这里的两个业务组件类定义了三个方法,用于模拟系统所包含三个业务逻辑方法,下面使用一个主程序来模拟系统调用两个业务组件的三个业务方法。

package com.afy.test;

import com.afy.app.service.Hello;
import com.afy.app.service.World;

public class AspectJTest{
    public static void main(String[] args){
        Hello hello = new Hello();
        hello.foo();
        hello.addUser("孙悟空" , "7788");
        World world = new World();
        world.bar();
    }
}

运行后程序输出如下。

现在假设客户要求在执行所有业务方法前先执行权限检查,如果使用传统的编程方式,开发者必须先定义一个权限检查的方法,然后由此打开每个业务逻辑方法,并修改业务方法的源代码,增加调用权限检查的方法,但这种方式需要对所有业务组件中的每个业务方法都进行修改,所以不仅容易引入新的错误,而且维护成本相当大。如果使用AspectJ的AOP支持,则只要添加如下特殊的”Java类”即可。

package com.afy.app.aspect;

public aspect AuthAspect {
    // 指定在执行org.crazyit.app.service包中任意类的、任意方法之前执行下面代码块
        // 第一个星号表示返回值不限;第二个星号表示类名不限;
        // 第三个星号表示方法名不限;圆括号中..代表任意个数、类型不限的形参
        before(): execution(* com.afy.app.service.*.*(..)){
            System.out.println("模拟进行权限检查...");
        }
}

运行程序,便可以看到神奇的事情发生了。

上面代码中不使用class、interface、enum等,而使用aspect,aspect不是Java支持的关键字,是AspectJ才能识别的关键字,AuthAspect不是一个Java类,代码主体里面不是方法,而是指定在执行某些类的某些方法之前,AspectJ会自动先调用该代码块中的代码。

从运行结果看,不需要对Hello.java、World.java等业务组件进行修改,但却能满足客户的需求。如果客户再次提出新需求,比如需要在执行所有业务方法之后增加记录日志的功能。这里我们再定义一个LogAspect,程序如下。

package com.afy.app.aspect;

public aspect LogAspect {
    //定义一个Pointcut,其名为logPointcut
    //该Pointcut代表了后面给出的切入点表达式,这样可服用该切入点表达式
    pointcut logPointcut()
        : execution(* com.afy.app.service.*.*(..));
    after():logPointcut(){
        System.out.println("模拟记录日志...");
    }
}

运行程序,结果会是酱紫。

可以吧!程序中定义了一个Pointcut: logPointcut(),这种用法就是为后面的切入点表达式起个名字,方便后面复用这个切入点表达式,如果程序中有多个代码块需要使用该切入点表达式,这些代码都可以直接复用自定义的logPointcut,而不用重复编写繁琐的切入点表达式。

如果现在需要在业务组件的所有业务方法之前启动事务,并在方法执行结束时关闭事务,只要添加TxAspect.java代码即可。

package com.afy.app.aspect;

import org.aspectj.lang.ProceedingJoinPoint;

public aspect TxAspect {
    //指定执行Hello.sayHello()方法时执行下面的代码块
    Object around() : call(* com.afy.app.service.*.*(..)) {
        System.out.println("模拟开启事务......");
        //回调原来的目标方法
        Object rvt = proceed();
        System.out.println("模拟结束事务......");
        return rvt;
    }
}

看我们程序的运行效果。

很强大哦,有不有!代码指定proceed()代表回调原来的目标方法,这样位于proceed()之前的代码就会被添加在目标方法之前,位于proceed()代码之后的代码就会添加在目标 方法之后。

时间: 2024-08-03 00:24:56

Spring(五)AOP的相关文章

Spring(五)AOP简述

一.AOP简述 AOP全称是:aspect-oriented programming,它是面向切面编号的思想核心, AOP和OOP既面向对象的编程语言,不相冲突,它们是两个相辅相成的设计模式型 AOP技术弥补了面向对象编程思想的不足,spring aop是实现aop的一种技术,srping aop是spring框架中某个子框架或者子功能所依赖的核心. SPring的容器并不依赖于AOP 这意味着程序员可以自己选择是否使用aop技术,aop提供强大的中间件解决方案,这使用spring ioc容器更

Spring框架第五篇之Spring与AOP

一.AOP概述 AOP(Aspect Orient Programming),面向切面编程,是面向对象编程OOP的一种补充.面向对象编程是从静态角度考虑程序的结构,而面向切面编程是从动态角度考虑程序运行过程. AOP底层就是采用动态代理模式实现的,采用了两种代理:JDK的动态代理与CGLIB的动态代理. 面向切面编程,就是将交叉业务逻辑封装成切面,利用AOP容器的功能将切面织入到主业务逻辑中.所谓交叉业务逻辑是指,通用的.与主业务逻辑无关的代码.如安全检查.事务.日志等. 若不是用AOP,则会出

跟着刚哥学习Spring框架--AOP(五)

AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.OOP引入封装.继承.多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合.不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能.日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性.异常处理和透明的持续性也都是如此,这种散布在各

Spring实现AOP的4种方式(转)

转自:http://blog.csdn.net/udbnny/article/details/5870076 Spring实现AOP的4种方式 先了解AOP的相关术语:1.通知(Advice):通知定义了切面是什么以及何时使用.描述了切面要完成的工作和何时需要执行这个工作.2.连接点(Joinpoint):程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法被调用时.异常被抛出时等等.3.切入点(Pointcut)通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的

Spring实现AOP的4种方式

来自:http://blog.csdn.net/udbnny/article/details/5870076 先了解AOP的相关术语: 1.通知(Advice):通知定义了切面是什么以及何时使用.描述了切面要完成的工作和何时需要执行这个工作.2.连接点(Joinpoint):程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法被调用时.异常被抛出时等等.3.切入点(Pointcut)通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的地点,例如某个类或方法的名称,S

spring的AOP

最近公司项目中需要添加一个日志记录功能,就是可以清楚的看到谁在什么时间做了什么事情,因为项目已经运行很长时间,这个最初没有开来进来,所以就用spring的面向切面编程来实现这个功能.在做的时候对spring的AOP还比较陌生,事后通过网上学习对其有了较好的了解. AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.OOP引入封装.继承.多态等概念来建立一种对象

Spring的AOP AspectJ切入点语法详解(转)

一.Spring AOP支持的AspectJ切入点指示符 切入点指示符用来指示切入点表达式目的,在Spring AOP中目前只有执行方法这一个连接点,Spring AOP支持的AspectJ切入点指示符如下: execution:用于匹配方法执行的连接点: within:用于匹配指定类型内的方法执行: this:用于匹配当前AOP代理对象类型的执行方法:注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配: target:用于匹配当前目标对象类型的执行方法:注意是目标对象的类型匹配,

【SSH进阶之路】Spring的AOP逐层深入——采用注解完成AOP(七)

上篇博文[SSH进阶之路]Spring的AOP逐层深入--AOP的基本原理(六),我们介绍了AOP的基本原理,以及5种通知的类型, AOP的两种配置方式:XML配置和Aspectj注解方式. 这篇我们使用注解方式来实现一个AOP,我们先看一下项目的目录. 我们采用的是JDK代理,所以首先将接口和实现类代码附上: package com.tgb.spring; public interface UserManager { public void addUser(String userName,St

Spring框架 AOP(三)

AOP理论概述 Aspect Oriented Programming 面向切面编程 业界 AOP 实际上 OOP (面向对象编程 ) 延伸 -- OOP编程语言. AOP设计思想 AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视.事务管理.安全检查.缓存) 横向抽取代码复用,基于代理技术,在不修改原有对象代码情况下,对原有对象方法功能进行增强! ---- AOP 思想 Spring框架如何实现AOP Spring1.2 版本开始 开始支持AOP技术 (传统Spring AOP

AOP、静态代理、JDK动态代理、CGLIB动态代理、Spring实现AOP、IOC+AOP

一.为什么需要代理模式 假设需实现一个计算的类Math.完成加.减.乘.除功能,如下所示: 1 package com.zhangguo.Spring041.aop01; 2 3 public class Math { 4 //加 5 public int add(int n1,int n2){ 6 int result=n1+n2; 7 System.out.println(n1+"+"+n2+"="+result); 8 return result; 9 } 1