spring AOP
今天我们学习spring的另外的一大核心,AOP,也就是面向切面编程.
简介
Aop关注的不再是程序代码中某个类,某些⽅法,⽽aop考虑的更多的是⼀种⾯到⾯的切⼊,即层与层之间的⼀种切⼊,所以称之为切⾯。
AOP主要应⽤于⽇志记录,性能统计,安全控制,事务处理等⽅⾯,实现公共功能性的重复使⽤。
AOP的底层实现:动态代理(JDK + CGLIB)
特点
- 降低模块与模块之间的耦合度,提⾼业务代码的聚合度。(⾼内聚低耦合)
- 提⾼了代码的复⽤性。
- 提⾼系统的扩展性。(⾼版本兼容低版本)
- 可以在不影响原有的功能基础上添加新的功能
AOP基本概念
Joinpoint(连接点):被拦截到的每个点,spring中指被拦截到的每⼀个⽅法
Pointcut(切⼊点):匹配的⽅法集合
Advice(通知):拦截到每⼀个连接点即(每⼀个⽅法)后所要做的操作
前置通知 (前置增强)— before() 执⾏⽅法前通知
返回通知(返回增强)— afterReturn ⽅法正常结束返回后的通知
异常抛出通知(异常抛出增强)— afetrThrow()
最终通知 — after ⽆论⽅法是否发⽣异常,均会执⾏该通知。
环绕通知 — around 包围⼀个连接点(join point)的通知,如⽅法调⽤。
Aspect(切⾯):切⼊点与通知的结合,决定了切⾯的定义
Target(⽬标对象):被代理的⽬标对象
Weave(织⼊):将切⾯应⽤到⽬标对象并⽣成代理对象的这个过程即为织⼊
Introduction(引⼊):在不修改原有应⽤程序代码的情况下,在程序运⾏期为类动态添加⽅法或者字段的过程称为引⼊
Aop 理解
- ⾯向切⾯,相⽐oop 关注的是代码中的层 或⾯
- 解耦,提⾼系统扩展性
- 提⾼代码复⽤
环境搭建
和spring ioc一样我们使用maven-quitstart,基础配置也是一样的
1>坐标依赖引⼊aspectjweaver
2>添加spring.xml的配置
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
AOP的实现
注解实现
配置⽂件(spring.xml)
<!--配置AOP代理-->
<aop:aspectj-autoproxy/>
定义切面
定义切入点:@Pointcut(“匹配规则”)
Aop 切入点表达式简介
1 . 执行任意公共方法:execution(public (…))
2. 执行任意的set方法: execution( set*(…))
3. 执行com.xxxx.service包下任意类的任意方法
execution(* com.xxxx.service..(…))
4. 执行com.xxxx.service 包 以及子包下任意类的任意方法
execution(* com.xxxx.service….(…))
注:表达式中的第一个* 代表的是方法的修饰范围
可选值:private、protected、public (* 表示所有范围)
@Component
@Aspect
public class UserService {
/**
* 切入点:
* 匹配规则。规定什么方法被拦截、需要处理什么方法
* 定义切入点
* @Pointcut("匹配规则")
*
* Aop 切入点表达式简介
* 1. 执行任意公共方法:
* execution(public *(..))
* 2. 执行任意的set方法
* execution(* set*(..))
* 3. 执行com.xxxx.service包下任意类的任意方法
* execution(* com.xxxx.service.*.*(..))
* 4. 执行com.xxxx.service 包 以及子包下任意类的任意方法
* execution(* com.xxxx.service..*.*(..))
*
* 注:表达式中的第一个* 代表的是方法的修饰范围
* 可选值:private、protected、public (* 表示所有范围)
*/
@Pointcut("execution (* com.xxxx.service..*.*(..) )")
public void cut(){};
@Before(value="cut()")
public void Before(){
System.out.println("前置通知");
}
@AfterReturning(value="cut()")
public void ar(){
System.out.println("返回通知");
}
@AfterThrowing(value="cut()",throwing ="e")
public void at(Exception e){
System.out.println("异常通知"+e.getCause());
}
@After(value="cut()")
public void after(){
System.out.println("最终通知");
}
}
public class App
{
public static void main( String[] args )
{
ApplicationContext ap=new ClassPathXmlApplicationContext("spring.xml");
UserService userService= (UserService) ap.getBean("userService");
userService.cut();
}
}
环绕通知
// @Around(value = "cut()")
public void around(ProceedingJoinPoint pjp){
//前置通知
System.out.println("环绕----前置通知");
try {
pjp.proceed(); //显示调用,放行 去执行目标方法
//正常执行 返回通知
System.out.println("环绕----返回通知");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("环绕----异常通知");
}
System.out.println("环绕----最终通知");
}
xml实现
定义切面
/**
* 切面(XML形式)
* 切入点和通知组成
*
* 切入点
* 增强哪些方法,使用规则匹配到一批方法
*/
@Service
public class UserAspectXml {
public void cut(){};
/**
* 前置通知
* 方法执行之前执行通知
*/
public void before(){
System.out.println("前置通知......方法执行之前执行通知");
}
/**
* 返回通知
* 方法正常执行完执行的通知
*/
public void afterReturn(){
System.out.println("返回通知.....方法正常执行完执行的通知");
}
/**
* 异常通知
* 方法正常执行完执行的通知
*/
public void afterThrow(Exception e){
System.out.println("异常通知......方法执行异常时完执行的通知 "+e.getMessage() );
}
/**
* 最终通知
* 方法执行结束之后执行的通知 (无论代码是否正常执行)
*/
public void after(){
System.out.println("最终通知......方法执行结束之后执行的通知");
}
/**
* 环绕通知
* 方法执行前后 通过环绕通知定义相应处理
* 需要通过显式调用对应的方法,否则无法访问指定方法 (pjp.proceed();)
*/
public void around(ProceedingJoinPoint pjp){
//前置通知
System.out.println("环绕----前置通知");
try {
pjp.proceed(); //显示调用,放行 去执行目标方法
//正常执行 返回通知
System.out.println("环绕----返回通知");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("环绕----异常通知");
}
System.out.println("环绕----最终通知");
}
}
配置文件(spring.xml)
<!--xml形式配置AOP-->
<aop:config>
<aop:aspect ref="userAspectXml">
<aop:pointcut id="cut" expression="execution(* com.xxxx.service..*.*(..))"/>
<aop:before method="before" pointcut-ref="cut" />
<aop:after method="after" pointcut-ref="cut"></aop:after>
<aop:after-returning method="afterReturn" pointcut-ref="cut"></aop:after-returning>
<aop:after-throwing method="afterThrow" pointcut-ref="cut" throwing="e"></aop:after-throwing>
<aop:around method="around" pointcut-ref="cut"></aop:around>
</aop:aspect>
</aop:config>