您现在的位置是:首页 >技术交流 >Spring:AOP 的详细内容网站首页技术交流
Spring:AOP 的详细内容
Spring:Day 03
AOP
一、概述
AOP:Aspect Oriented Programming,面向切面编程,是通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。
本质:动态代理
AOP 实现的目的:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。而应用对象只实现它们应该做的,例如完成业务逻辑,它们并不负责其它的系统级关注点,例如日志或事务支持。
功能和作用:利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
名词解释:
- 切面(Aspect):一个关注点的模块化,可以是自定义的一个类(用来存放对被代理对象进行的额外操作),用注解
@Aspect
在自定义类上方声明,表示该类为一个切面; - 连接点(Joinpoint):在程序执行过程中某个特定的点,一个切面中的所有方法都是连接点;
- 切点(Pointcut):从连接点中筛选出一些作为切点,切点指定了执行的地点;
- 通知(Advice):通知增强,需要在切点处完成的工作叫做通知,例如日志记录,性能统计,安全控制,事务处理,异常处理等;
- 织入(Weavy):将切面应用到被代理对象,并使得代理对象被创建的过程称为织入。
二、搭建环境
- 使用 AOP 织入,需要导入一个依赖
<!-- aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
- 准备一个接口(用来定义要执行的业务)和实现类(被代理对象)
- 接下来,将使用三种不同的方式来实现 AOP,即实现动态代理:
- 方式一:使用原生 Spring 的 API 接口;
- 方式二:自定义类(切面);
- 方式三:注解。
三、实现 AOP
1. 方式一:使用原生 Spring 的 API 接口
方法:
- 编写前置类实现
MethodBeforeAdvice
接口;后置类实现AfterReturningAdvice
接口; - 重写方法:
method
表示执行的方法;args
表示方法的参数;target
表示被代理对象;returnValue
表示返回值; - 编写配置文件
applicationContext.xml
,注册 bean,导入 aop 约束,配置 aop(包括设置切入点和执行环绕增加); - 测试。
- 编写前置类和后置类
- 配置文件
- 测试
注意点:
在配置文件中导入 aop 约束时,可以:
<aop:config> + 回车
自动导入;可以设置多个切入点,其中 execution 表达式指定了要切入的位置,表达式的语法为:
execution(修饰符 返回值类型 包.类.方法名(参数) throws异常)
:
- 修饰符:一般省略;
- 返回值类型:不能省略,可以为 void、String 或者任意类型;
- 包.类.方法名:类和方法名可以用 * 表示所有,方法名不能省略,因此小括号前的就是方法名;
- 参数:可以为无参 ()、指定类型 (int, String)、任意参数代替 (…);
- throws 异常:一般省略。
如:
execution(* com.Sun3285.service.UserServiceImpl.*(..))
表示返回值为任意类型、UserServiceImpl 类的任意方法、任意参数。动态代理代理的是接口,因此测试时,返回值类型一定是接口的类型;
通过 aop 配置,前置类中的方法会在调用业务方法之前执行,后置类中的方法会在调用业务方法之后执行,和动态代理的执行流程一样;
这样就实现了被代理对象执行业务与代理做额外的操作相互分离,最后由 Spring 来执行一个 aop 切入就可以实现代理过程。
2. 方式二:自定义类(切面)
方法:
- 编写一个自定义的类,里面定义一些方法,这些方法是代理需要做的额外操作;
- 编写配置文件
applicationContext.xml
,注册 bean,导入 aop 约束,配置 aop; - 测试。
- 自定义的类,存放一些代理需要做的额外操作
- 配置文件
- 测试
3. 方式三:注解
方式三使用注解是对方式二的简化:将配置 aop 的步骤用注解代替了之前的 xml 配置。
使用到的注解有:
注解 | 说明 |
---|---|
@Aspect | 标注在类上,标注这个类是一个切面 |
@Before(“execution(切入点位置)”) | 标注在方法上,在切入点之前执行该方法 |
@After(“execution(切入点位置)”) | 标注在方法上,在切入点之后执行该方法 |
注意:
- @Aspect:相当于配置文件中的
<aop:aspect ref="要引用类的 bean id">
;- @Before:相当于配置文件中的
<aop:before method="方法" pointcut-ref="切入点"/>
;- @After:相当于配置文件中的
<aop:after method="方法" pointcut-ref="切入点"/>
。
使用注解实现 AOP 的方法:
- 【与方式二相同】编写一个自定义的类,里面定义一些方法,这些方法是代理需要做的额外操作;
- 【与方式二相同】编写配置文件
applicationContext.xml
,注册 bean,导入 aop 约束; - 在配置文件中开启注解支持:
<aop:aspectj-autoproxy/>
; - 使用注解配置 aop;
- 测试。
- 配置文件
- 注解配置 aop
- 测试
注意:导入注解的包为
org.aspectj.lang.annotation
下的包。
四、总结
-
总的来说,AOP 就是在不影响原来业务类的情况下,对业务进行动态地增强。
-
实现 AOP 的方式有三种:
- 方式一:可以通过反射得到被代理对象的一些信息,本质是动态代理,功能更强大;
- 方式二:不能获取被代理对象的信息,可以只做一些与被代理对象无关的额外的操作;
- 方式三:使用注解是对方式二的简化,配置 AOP 时用注解代替了之前的 xml 配置。
-
三种实现方式配置 AOP 时:
- 方式一:配置文件中,使用
aop:pointcut
设置切入点,然后aop:advisor
设置环绕增加; - 方式二:配置文件中,先使用
aop:aspect
自定义切面,然后使用aop:pointcut
设置切入点,使用aop:before
或aop:after
决定方法的执行前后; - 方式三:使用注解配置。
- 方式一:配置文件中,使用
-
在方式一中,代理的额外操作是否在业务方法前后,是由实现的原生 Spring 的 API 接口决定的;
-
所有的类都需要注册为 bean。