一起玩转微服务(13)——AOP
一、什么是AOP编程
AOP: Aspect Oriented Programming 面向切面编程。 面向切面编程(也叫面向方面):Aspect Oriented Programming(AOP),是目前软件开发中的一个热点。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。 AOP是OOP的延续,是(Aspect Oriented Programming)的缩写,意思是面向切面(方面)编程。 主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。 主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改 变这些行为的时候不影响业务逻辑的代码。
注意:AOP不是一种技术,实际上是编程思想。凡是符合AOP思想的技术,都可以看成是AOP的实现。
二、AOP编程思想
功能: 让关注点代码与业务代码分离!
- 关注点
关注点,重复代码就叫做关注点; - 切面
关注点形成的类,就叫切面(类)!
面向切面编程,就是指 对很多功能都有的重复的代码抽取,再在运行的时候网业务方法上动态植入“切面类代码”。 - 切入点
执行目标对象方法,动态植入切面代码。
可以通过切入点表达式,指定拦截哪些类的哪些方法; 给指定的类在运行的时候植入切面类代码。
三、AOP原理剖析
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,它们经常发生在核心关注点的多处,而各处都基本相似,比如权限认证、日志、事务处理。AOP 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
AOP中的一些名词如下:
- 切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。在Spring AOP中,切面可以使用基于模式或者基于@Aspect注解的方式来实现。
- 连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点总是表示一个方法的执行。
- 通知(Advice):在切面的某个特定的连接点上执行的动作。其中包括了“around”、“before”和“after”等不同类型的通知(通知的类型将在后面部分进行讨论)。许多AOP框架(包括Spring)都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。
- 切入点(Pointcut):匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法进行匹配。
- 引入(Introduction):用来给一个类型声明额外的方法或属性(也被称为连接类型声明(inter-type declaration))。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用引入来使一个bean实现IsModified接口,以便简化缓存机制。
- 目标对象(Target Object):被一个或者多个切面所通知的对象。也被称做被通知(advised)对象。既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。
- AOP代理(AOP Proxy):AOP框架创建的对象,用来实现切面契约(例如通知方法执行等等)。在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
- 织入(Weaving):把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
四、AOP编程使用
注解版本实现AOP
<aop:aspectj-autoproxy></aop:aspectj-autoproxy> 开启事物注解权限 @Aspect 指定一个类为切面类 @Pointcut("execution(* com.service.UserService.add(..))") 指定切入点表达式 @Before("pointCut_()") 前置通知: 目标方法之前执行 @After("pointCut_()") 后置通知:目标方法之后执行(始终执行) @AfterReturning("pointCut_()") 返回后通知: 执行方法结束前执行(异常不执行) @AfterThrowing("pointCut_()") 异常通知: 出现异常时候执行 @Around("pointCut_()") 环绕通知: 环绕目标方法执行 @Component @Aspect public class AopLog { // 前置通知 @Before("execution(* com.service.UserService.add(..))") public void begin() { System.out.println("前置通知"); } // 后置通知 @After("execution(* com.service.UserService.add(..))") public void commit() { System.out.println("后置通知"); } // 运行通知 @AfterReturning("execution(* com.service.UserService.add(..))") public void returning() { System.out.println("运行通知"); } // 异常通知 @AfterThrowing("execution(* com.service.UserService.add(..))") public void afterThrowing() { System.out.println("异常通知"); } // 环绕通知 @Around("execution(* com.service.UserService.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕通知开始"); proceedingJoinPoint.proceed(); System.out.println("环绕通知结束"); } }