Aop基础使用
1.什么是AOP
AOP:Aspect Oriented Programming,中文翻译为”面向切面编程“。
面向切面编程是一种编程范式,它作为OOP面向对象编程的一种补充,用于处理系统中分布于各个模块的横切关注点,
比如事务管理、权限控制、缓存控制、日志打印等等。AOP采取横向抽取机制,取代了传统纵向继承体系的重复性代码
2.专业名词
英文 | 中文 | 描述 |
---|---|---|
Joinpoint | 连接点 | 类里面可以被增强的方法,这些方法称为连接点 |
Pointcut | 切入点 | 所谓切入点是指我们要对哪些Joinpoint进行拦截的定义 |
Advice | 通知/增强 | 所谓通知是指拦截到Joinpoint之后所要做的事情就是通知 通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能) |
Advisor | 通知器 | 其实就是切点和通知的结合 |
Aspect | 切面 | 表示Pointcut(切入点)和Advice(增强/通知)的结合 |
Target | 目标对象 | 被代理对象 |
3.注解
注解 | 描述 |
---|---|
@EnableAspectJAutoProxy | 开启自动切面代理,设置需要执行切面的 |
@Aspect | 标注增强类 |
@Before | 前置通知 |
@After | 后置通知 |
@AfterReturning | 返回通知 |
@AfterThrowing | 异常通知 |
@Around | 环绕通知 |
4.切入点表达式execution
-
切入点表达式作用:我们可以通过表达式,来标注对增强类的哪些方法进行增强
-
语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称] [(参数列表)] )
- 举例 1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强
execution(* com.atguigu.dao.BookDao.add(…)) - 举例 2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强
execution(* com.atguigu.dao.BookDao.* (…)) - 举例 3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强
execution(* com.atguigu.dao.. (…)) - 举例 4:对 com.atguigu.dao 包里面所有类,类里面的公共方法进行增强
execution(public * com.atguigu.dao.. (…))
- 举例 1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强
相同的切入点
// 相同切入点抽取 下面避免重复使用
@Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void pointCur() {
}
@Before(value = "pointCur()")
...
增强类优先级@Order
当有多个增强类类同一个方法进行增强,那么可以通过@Order
设置优先级,数字类型值越小优先级越高
@Component
@Aspect
@Order(1)
public class PersonProxy{}
5.示例代码
a> 需要的依赖
// junit
hamcrest-core-1.1.jar
junit-4.12.jar
// Aop
aopalliance-1.0.jar
aspectjrt-1.9.6.jar
aspectjweaver-1.9.7.jar
cglib-3.2.0.jar
commons-logging-1.1.1.jar
spring-aop-5.1.5.RELEASE.jar
spring-aspects-5.3.13.jar
// Spring核心注解
spring-beans-5.1.5.RELEASE.jar
spring-context-5.1.5.RELEASE.jar
spring-core-5.1.5.RELEASE.jar
spring-expression-5.1.5.RELEASE.jar
b> 切面类
// 定义一个方法,执行切面方法
@Component
public class MathCalculator {
public int div(int i, int j) {
System.out.println("执行 div 方法");
return i / j;
}
}
c> 增强类
package com.jianan.spring5.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
@Component
@Aspect
public class LogAspect {
@Pointcut(value = "execution(public int com.jianan.spring5.aop.MathCalculator.*(..))")
public void pointCur() {
}
@Before(value = "pointCur()")
public void before(JoinPoint joinPoint) {
// 参数
Object[] args = joinPoint.getArgs();
// 切面方法信息
Signature signature = joinPoint.getSignature();
// 切面方法名
String name = signature.getName();
// 切面方法权限修饰符
int modifiers = signature.getModifiers();
// 切面类Class
Class declaringType = signature.getDeclaringType();
// 切面包名+类名
String declaringTypeName = signature.getDeclaringTypeName();
System.out.println("----before-----");
}
@After(value = "pointCur()")
public void after(JoinPoint joinPoint) {
System.out.println("----after----");
}
@AfterReturning(value = "pointCur()", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println("-----afterReturning------- 返回值:" + result);
}
@AfterThrowing(value = "pointCur()", throwing = "e")
public void afterThrowing(JoinPoint joinPoint, Exception e) {
System.out.println("------joinPoint------- 异常:" + e.getMessage());
}
@Around(value = "pointCur()")
public Object around(ProceedingJoinPoint joinPoint) {
System.out.println("------around------");
Object result = null;
try {
Object[] args = joinPoint.getArgs();
result = joinPoint.proceed(args);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return result;
}
}
b> 配置类
package com.jianan.spring5.aop;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@EnableAspectJAutoProxy
@Configuration
@ComponentScan(basePackages = "com.jianan")
public class AspectConfig {
}
d> 测试
@Test
public void m1() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AspectConfig.class);
MathCalculator mathCalculator = context.getBean(MathCalculator.class);
int ans = mathCalculator.div(10, 5);
System.out.println("结果:" + ans);
}
e> 结果
------around------
----before-----
执行 div 方法
----after----
-----afterReturning------- 返回值:2
结果:2