(五)Spring 中的 aop
目录
AOP概念
-
浅理解
aop:面向切面编程,扩展功能不需要修改程序源代码 ; -
深度理解
aop:采取了横向抽取机制,取代了传统纵向继承体系复杂性代码 ;概念看完,不一定懂,aop 到底是怎么完成不修改源代码,,而进行功能扩展的 ; 往下看 原理 ;
AOP原理
-
传统的
纵向继承体系想要对功能进行扩展,最原始的做法是:修改源代码,在源代码上直接添加功能代码;但是,这样做,会产生了一个
问题:假如有几个方法,都要增加一个相同的功能,就务必会有重复性代码的产生;后来有人想到了
纵向继承体系,就像图中的那样,要增强功能的时候,写一个基类,然后让要扩展的类,继承基类,达到扩展功能的目的 ;这样解决了重复代码的问题,但是还有问题,就是扩展类和基类绑定在一起了,耦合高,只要基类方法改名字,要扩展的类,就得相应的改名字 ; -
aop的横向抽取一(有接口JDK动态代理)Spring的aop底层是使用动态代理实现的 ;动态代理分为2中,有接口、无接口 ; -
aop的横向抽取二(没有接口cglib)动态代理怎么操作的,这里不讲,这里主要表达aop底层是动态代理;
AOP术语
-
Joinpoint(连接点)
官方解释:就是那些被拦截到的点,在Spring中这些点就是方法,因为 spring 只支持方法类型的连接点 ;大白话:就是类里面,可以 被增强的方法 ; -
Pointcut(切入点)官方解释:对连接点进行拦截的定义 ;大白话:类中 实际 被增强的方法 ; -
Advice(通知、增强)官方解释:拦截到连接点以后,要做的事;通知分为:前置通知、后置通知、异常通知、最终通知、环绕通重点内容`(切面要完成的功能)大白话:实际要扩展的功能 ;前置通知:在原方法执行之前,进行功能的扩展 ;
后置通知:在原方法执行之后,进行功能的扩展 ;
异常通知:在方法出现异常的还是,进行功能的扩展 ;
最终通知:在后置通知之后,进行功能的扩展 ;
环绕通知:在方法之前和之后,都进行功能的扩展 ; -
Introduction(引介)
是一种特殊的通知,在不修改类代码的前提下,Introduction 可以在运行期为类动态的添加一些方法或者字段 ;
-
Target(目标对象)
代理的目标对象,即要增强的类 ;
-
Weaving(植入)
把要增强应用到目标的过程 ;
-
Proxy(代理)
一个类被 AOP 植入增强以后,就会产生一个代理类 ;
-
Aspect(切面)官方解释:切入点和通知(引介)的结合;大白话:把扩展的功能,应用到要增强的方法上的过程 ;
Spring 中的 aop 的操作
AspectJ 框架
Aspect是一个面向切面的框架(不是Spring里面的,是一个独立的框架,可以和Spring搭配使用),它扩展了java语言。AspectJ定义了AOP语法,所以它有一个专门的编译器用来生成遵守java字节编码规范的Class文件 ;AspectJ是一个基于java语言的AOP框架;Spring2.0以后新增了对AspectJ切点表达式支持;@AspectJ是AspectJ 1.5新增功能,通过JDK注解技术,允许直接在Bean类中定义切面 ;- 新版本
Spring框架,建议使用AspectJ方式来开发AOP; - 使用
AspectJ需要导入Spring aop和AspectJ相关的jar包 ;
使用 AspectJ 实现 aop 的两种方式
-
基于
AspectJ的配置方式-
导包除了
Spring-aop的包,还需要AspectJ的aopalliance-1.0、aspectjweaver-1.8.11两个包 ; -
配置文件添加新的约束添加 aop 的相关约束
xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation= "http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd" -
使用表达式配置切入点常用表达式:
execution(<访问修饰符>?<返回类型><方法名>(参数)<异常>例如:
写法:
execution(*+空格+方法名全路径)// 匹配 包路径xin.ijava.aop 下面的 Book 类的 add()方法 // * 表示任意都匹配 写在这里匹配保护:public、private、abstract // add(..) 表示匹配由于参数都行 execution(* xin.ijava.aop.Book.add(..)) ------------------------------------- // 匹配 包路径xin.ijava.aop 下面的 Book 类的 所有方法 execution(* xin.ijava.aop.Book.*(..)) ------------------------------------- // 匹配 包路径xin.ijava.aop 下面的所有方法(不包含子包) execution(* xin.ijava.aop.*(..)) ------------------------------------- // 匹配 包路径xin.ijava.aop 下面的所有方法(包含子包) execution(* xin.ijava.aop..*(..)) ------------------------------------- // 匹配 任意包路径下面的任意类的任意方法 execution(* *.*(..)) ------------------------------------- // 匹配 所有以 add 开头的方法 execution(* add*(..)) ------------------------------------- // 匹配 实现特定接口(xin.ijava.aop.dao)的所有类方法 execution(* xin.ijava.aop.dao+*(..)) -
在配置文件中配置切入点
<aop:config> <!--配置切入点--> <aop:pointcut id="bookPointCut" expression="execution(* ijava.xin.aop.Book.*(..))"/> <!--配置切面--> <!--ref 中是 增强对象,不是要增强的对象--> <aop:aspect ref="bookAdvice"> <!--前置通知--> <aop:before method="beforeAdd" pointcut-ref="bookPointCut"></aop:before> </aop:aspect> </aop:config> -
环绕通知环绕通知和其他通知,有点不一样增强对象中,
环绕通知方法的代码:/** * 环绕通知 * @param proceedingJoinPoint 参数 */ public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("前置通知.."); // 调用增强的方法 proceedingJoinPoint.proceed() ; System.out.println("后置通知.."); }
-
-
基于
AspectJ的注解方式-
在
Spring 配置文件中开启AOP自动代理<!--开启aop自动代理--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> -
然后在
增强类上面写一个@Aspect注解 ; -
在要
增强类的增强方法上写注解,配置切入点
@Component("bookAdvice") @Aspect public class BookAdvice { @Before(value = "execution(* ijava.xin.aop.Book.*(..))") public void beforeAdd(){ System.out.println("前置通知.."); } /** * 环绕通知 * @param proceedingJoinPoint 参数 */ @Around(value = "execution(* *.*(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("前置通知1.."); // 调用增强的方法 proceedingJoinPoint.proceed() ; System.out.println("后置通知1.."); } } -
border="0" src="//music.163.com/outchain/player?type=2&id=1297001123&auto=1&height=66" width="1" height="0">

浙公网安备 33010602011771号