JavaWeb 之 Spring AOP 面向切面编程
Spring AOP 面向切面编程
Spring 框架核心功能之 AOP 技术
AOP 的概述
什么是 AOP 的技术?
- 在软件业,AOP 为 Aspect Oriented Programming 的缩写,意为:
面向切面编程
。 - AOP 是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构。
- AOP 最早由 AOP 联盟的组织提出的,制定了一套规范。Spring 将 AOP 思想引入到框架中,必须遵守 AOP 联盟的规范。
- 通过
预编译方式和运行期动态代理
实现程序功能的统一维护的一种技术。 - AOP 是
OOP 的延续
,是软件开发中的一个热点,也是 Spring 框架中的一个重要内容,是函数式编程的一种衍生范型。 - 利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的
耦合度降低
,提高程序的可重用性
,同时提高了开发的效率。
- AOP:面向切面编程。(思想————解决
OOP
遇到一些问题) - AOP 采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)
为什么要学习 AOP
- 可以在不修改源代码的前提下,对程序进行增强!
Spring 框架的 AOP 的底层实现
代理方式
Srping 框架的 AOP 技术底层也是采用的代理技术,代理的方式提供了两种
基于
JDK
的动态代理必须是面向接口的,只有实现了具体接口的类才能生成代理对象
基于
CGLIB
动态代理对于没有实现了接口的类,也可以产生代理,产生这个类的子类的方式
Spring 的传统 AOP 中根据类是否实现接口,来采用不同的代理方式
如果实现类接口,使用
JDK
动态代理完成 AOP如果没有实现接口,采用
CGLIB
动态代理完成 AOP
JDK 的动态代理(代码了解,理解原理)
使用 Proxy
类来生成代理对象的一些代码如下:
注意:得有接口才能使用。
1 | /** |
测试:
1 | public class demo1 { |
CGLIB 的代理技术(了解)
- 引入
CBLIB
的开发包如果想使用
CGLIB
的技术来生成代理对象,那么需要引入CGLIB
的开发的jar
包,在Spring
框架核心包中已经引入了CGLIB
的开发包了。所以直接引入Spring
核心开发包即可!
编写相关的代码
1 | public class MyCglibUtils { |
测试:
1 |
|
Spring 基于 AspectJ 的 AOP 的开发
AOP 的相关术语
Joinpoint(连接点)
————所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点Pointcut(切入点)
————所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义Advice(通知/增强)
————所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)Introduction(引介)
————引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 FieldTarget(目标对象)
————代理的目标对象Weaving(织入)
————是指把增强应用到目标对象来创建新的代理对象的过程Proxy(代理)
————一个类被 AOP 织入增强后,就产生一个结果代理类Aspect(切面)
————是切入点和通知的结合,需要自己来编写和配置的
具体点就是:
连接点:UserDaoImpl 中的所有方法都可以称为连接点。
切入点:拦截哪些方法(对哪些方法进行增强)。
通知/增强:具体做什么功能,比如记录日志。
目标对象:UserDaoImpl 称为目标对象。
织入:把增强添加到目标对象,生成代理对象的过程。
代理:生成的代理对象。
切面:切入点 + 通知,组合称为切面。通知需要自己来编写,切入点需要配置。
AspectJ 的 XML 方式完成 AOP 开发
第一个案例
步骤一:创建 JavaWEB 项目,引入具体的开发的 jar 包
先引入 Spring 框架开发的基本开发包(6个)
再引入 Spring 框架的 AOP 的开发包(4个)
- Spring 的传统
AOP
的开发的包spring-aop-4.2.4.RELEASE.jar
com.springsource.org.aopalliance-1.0.0.jar
- Spring 的传统
aspectJ
的开发包com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aspects-4.2.4.RELEASE.jar
步骤二:创建 Spring 的配置文件,引入具体的 AOP 的 schema 约束
1 | <beans xmlns="http://www.springframework.org/schema/beans" |
步骤三:创建包结构,编写具体的接口和实现类
- com.renkaigis.demo4
CustomerDao – 接口
CustomerDaoImpl – 实现类
步骤四:将目标类配置到 Spring 中
1 | <!--配置客户的 dao--> |
步骤五:定义切面类
1 | /** |
步骤六:在配置文件中定义切面类
1 | <!--配置切面类--> |
步骤七:在配置文件中完成aop的配置
1 | <!--配置 AOP--> |
完成测试
1 | /** |
切入点的表达式
在配置切入点的时候,需要定义表达式,重点的格式如下:execution(public * *(..))
,具体展开如下:
切入点表达式的格式如下:
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
修饰符可以省略不写,不是必须要出现的。
返回值类型是不能省略不写的,根据你的方法来编写返回值。可以使用
*
代替。包名例如:com.renkaigis.demo4.BookDaoImpl
首先 com 是不能省略不写的,但是可以使用
*
代替
中间的包名可以使用*
号代替
如果想省略中间的包名可以使用*..*
类名也可以使用
*
号代替,也有类似的写法:*DaoImpl
方法也可以使用
*
号代替,save*()
参数如果是一个参数可以使用
*
号代替,如果想代表任意参数使用..
1 | <aop:aspect ref="myAspectXml"> |
AOP的通知类型
前置通知
在目标类的方法执行之前执行。
配置文件信息:<aop:after method="before" pointcut-ref="myPointcut3"/>
应用:可以对方法的参数来做校验最终通知
在目标类的方法执行之后执行,如果程序出现了异常,最终通知也会执行。
配置文件信息:<aop:after method="after" pointcut-ref="myPointcut3"/>
应用:例如像释放资源后置通知
方法正常执行后的通知。出现异常,不会执行。
配置文件信息:<aop:after-returning method="afterReturning" pointcut-ref="myPointcut2"/>
应用:可以修改方法的返回值异常抛出通知
在抛出异常后通知
配置文件信息:<aop:after-throwing method="afterThorwing" pointcut-ref="myPointcut3"/>
应用:包装异常的信息环绕通知
方法的执行前后执行。
配置文件信息:<aop:around method="around" pointcut-ref="myPointcut2"/>
要注意:目标的方法默认不执行,需要使用 ProceedingJoinPoint 对来让目标对象的方法执行。
1 | /** |
Spring框架的AOP技术之注解方式
第一个案例
步骤一:创建 JavaWEB 项目,引入具体的开发的 jar 包
同上。
步骤二:创建 Spring 的配置文件,引入具体的 AOP 的 schema 约束
同上。
这里我引入一个最全的约束:
1 | <beans xmlns="http://www.springframework.org/schema/beans" |
步骤三:创建包结构,编写具体的接口和实现类
- com.renkaigis.demo5
CustomerDao————接口
CustomerDaoImpl————实现类
步骤四:将目标类配置到 Spring 中
1 | <!--配置客户的 dao--> |
步骤四:将目标类配置到 Spring 中
1 | <!--配置目标对象--> |
步骤五:定义切面类
添加切面和通知的注解
@Aspect
————定义切面类的注解通知类型(
注解的参数是切入点的表达式
)@Before————前置通知
@AfterReturing————后置通知
@Around————环绕通知
@After————最终通知
@AfterThrowing————异常抛出通知
具体的代码如下
1 | /** |
步骤六:在配置文件中定义切面类
1 | <!--配置切面类--> |
步骤七:在配置文件中开启自动代理
1 | <!--开启自动代理--> |
步骤八:完成测试
1 | /** |
通知类型
通知类型
@Before
————前置通知@AfterReturing
————后置通知@Around
————环绕通知(目标对象方法默认不执行的,需要手动执行)@After
————最终通知@AfterThrowing
————异常抛出通知
配置通用的切入点
- 使用
@Pointcut
定义通用的切入点
1 |
|