Spring AOP详解
原文地址:Spring AOP详解
写在最前
讲完IoC,那么下面就开始讲AOP。对于系统中普通的业务关注点,OOP可以很好地对其进行分解并使之模块化,但却无法更好地避免类似于系统需求的实现在系统中各处散落这样的问题。所以,我们要寻求一种更好的方法,它可以在OOP的基础上更上一层楼,提出一套全新的方法论来避免以上问题,也可以提供某种方法对基于OOP的开发模式做-一个补足,帮助OOP以更好的方式解决以上问题。但迄今为止,我们还找不到比OOP更加有效的软件开发模式。不过,好消息是,我们找到了后者,那就是AOP。
AOP的概念
AOP全称为Aspect-Oriented Programming,中文通常翻译为面向方面编程。使用AOP,我们可以对类似于Logging和Security等系统需求进行模块化的组织,简化系统需求与实现之间的对比关系,进而使得整个系统的实现更具模块化。
怎么来理解呢?
下面就拿我们最常见的代码开始说起吧
下图是我们经常会写到的代码结构
我们这时候通常已经降事务的代码封装成一个类了,然后开启事务,提交事务,回滚事务都是调用的封装类的某个方法。但是我们发现,在每一个Service里面,我们几乎都会写上这样的代码。写一个还好,写十个,百个呢?肯定会写到抓狂。而且,对于我们一直提倡的解耦解耦,这种代码明显是破坏了我们的解耦理念的,业务的代码在某种程度上被污染了。
那怎么办?
我们可能第一时间想到的是抽,继续抽。但其实是不行的。因为这些事务逻辑是依附到我们的业务类逻辑方法中的。而且,我们常说的抽取,是纵向抽取,纵向的抽取在这个时候已经到极限了(都只剩一行代码了)。
那我们重新回来想想,现在想的是把事务代码剔除出去,不让它来污染我们的代码,也就是下面这样
然后明确我们的目的,也就是要在业务逻辑含有我们事务的功能,也就是增强我们的业务逻辑或者说装饰我们的业务逻辑但又不影响我们业务本身的代码。说到这个时候,就是不是想起了某个我们熟悉的东西?没错,我们可以使用装饰者模式,JAVA中的动态代理来实现这种功能~~(也就是来套娃)~~
所以回到正题,最后我们的这样抽取,也就是横向抽取,就叫做面向切面编程。之所以这么叫,可以看下书中的图
与主要业务逻辑无关的需求,就要切面一样插入到业务中,实现了业务的系统需求。
AOP的术语
豆知识
书上介绍了蛮多,但我还是挑重点记录一下
AOP的实现很多,将AOP的Aspect织入到OOP系统的实现方式可谓千差万别。但不管如何实现,织入过程是处于AOP和OOP的开发过程之外的,而且对于整个系统的实现是透明的,开发者只需要关注相应的业务需求实现,或者系统需求的实现即可。当所有业务需求和系统需求以模块化的形式开发完成之后,通过织入过程就可以将整个的软件系统集成并付诸使用。
AOP的实现也分为静态AOP实现和动态AOP实现
其中Spring是使用的动态AOP实现
Java平台上的AOP实现机制
- 动态代理
- 动态字节码增强
- Java代码生成
- 自定义类加载器
- AOL拓展
需要掌握的术语
Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。
Pointcut(切入点):指我们要对哪些 Joinpoint 进行拦截的定义。更通俗的说,就是我们要增强的方法。
Advice(通知/ 增强):指拦截到 Joinpoint 之后所要做的事情就是通知。相当于Class中的Method。通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
Aspect(切面):是Pointcut和Advice的结合。
Target(目标对象):代理的目标对象。
Weaving(织入):指把增强应用到目标对象来创建新的代理对象的过程。spring 采用动态代理织入
Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类。
Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 Field。SpringAOP没实现。。。
开始使用之前
在使用之前,先翻一翻Spring文档
5.6.1. Spring AOP or Full AspectJ?
Use the simplest thing that can work. Spring AOP is simpler than using full AspectJ, as there is no requirement to introduce the AspectJ compiler / weaver into your development and build processes. If you only need to advise the execution of operations on Spring beans, Spring AOP is the right choice. If you need to advise objects not managed by the Spring container (such as domain objects, typically), you need to use AspectJ. You also need to use AspectJ if you wish to advise join points other than simple method executions (for example, field get or set join points and so on).
When you use AspectJ, you have the choice of the AspectJ language syntax (also known as the “code style”) or the @AspectJ annotation style. Clearly, if you do not use Java 5+, the choice has been made for you: Use the code style. If aspects play a large role in your design, and you are able to use the AspectJ Development Tools (AJDT) plugin for Eclipse, the AspectJ language syntax is the preferred option. It is cleaner and simpler because the language was purposefully designed for writing aspects. If you do not use Eclipse or have only a few aspects that do not play a major role in your application, you may want to consider using the @AspectJ style, sticking with regular Java compilation in your IDE, and adding an aspect weaving phase to your build script.
大意是Spring实现了一些该实现的东西,但是,如果你有其他需求的话,需要引入完整的AspectJ。所以,我还是两个都引入吧。。。aspectj主要是用来解析execution里面的表达式的
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
使用AOP
XML形式
直接上代码,结合代码说吧
下面是我我单独抽取出来的日志通知对象
package com.chayedan.util;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype