一、Spring AOP
AOP(Aspect Oriented Programming) 是一种面向切面的编程思想。面向切面编程是将程序抽象成各个切面,即解剖对象的内部,将那些影响了多个类的公共行为抽取到一个可重用模块里,减少系统的重复代码,降低模块间的耦合度,增强代码的可操作性和可维护性。
其中的核心概念:
名称 | 说明 |
Joinpoint(连接点) | 指那些被拦截的点,在spring中,指可以被动态代理拦截目标类的方法 |
Pointcut(切入点) | 指要对哪些 Jointpoint 进行拦截,即被拦截的连接点 |
Advice(通知) | 指拦截到 Joinpoint 之后要做的事情,即对切入点增强的内容 |
Target(目标) | 指代理的目标对象 |
Weaving(植入) | 指把增强代码应用到目标上,生成代理对象的过程 |
Proxy(代理) | 指生成的代理对象 |
Aspect(切面) | 切入点和通知的结合 |
二、AOP的使用场景
AOP可以拦截指定的方法,并且对方法增强,比如:事务、日志、权限、性能监测等增强,而且无需侵入到业务代码中,使业务与非业务处理逻辑分离。
三、AOP的通知分类以及代码示例
1、通知的分类
2、代码示例
(1)pom.xml中导入依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
(2)新建配置类LogAspectConfig,使用 @Component、@Aspect 定义切面,@Pointcut定义切点
@Component
@Aspect
public class LogAspectConfig {
// 匹配指定包中的所有方法
//execution(* org.example.service.*(..))
// 匹配当前包中的所有public方法
//execution(public * UserService.*(..))
// 匹配指定包中的所有public方法,并且返回值是int类型的方法
//execution(public int org.example.service.*(..))
// 切点
@Pointcut("execution(* org.example.controller.*.*(..))")
public void operationLog(){};
/**
* 方法执行前调用
* @param joinPoint
*/
@Before("operationLog()")
public void TestBefore(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println("即将调用该方法:" + methodName);
}
/**
* 方法调用后执行
* @param joinPoint
*/
@After("operationLog()")
public void afterHandler(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
String name = joinPoint.getSignature().getName();
System.out.println("入参:" + Arrays.asList(args).toString() + ",调用方法名称:" + name);
System.out.println("调用方法之后");
}
/**
* 调用方法并正常返回后执行
*/
@AfterReturning("operationLog()")
public void afterReturningHandler() {
System.out.println("调用方法并正常返回后执行");
}
/**
* 调用方法却抛出异常后执行
*/
@AfterThrowing("operationLog()")
public void afterThrowingHandler() {
System.out.println("调用方法却抛出异常后执行");
}
/**
* 环绕增强,能控制切点执行前,执行后
* @param joinPoint
* @return
*/
@Around("operationLog()")
public Object doAround(ProceedingJoinPoint joinPoint) {
Object proceed = null;
try {
System.out.println("方法执行前");
proceed = joinPoint.proceed();
System.out.println("方法执行后");
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return proceed;
}
}
(3)创建CommonController
@RestController
@RequestMapping("/text")
public class CommonController {
@GetMapping("/query/{id}")
public String query(@PathVariable int id) {
if ( 1 == id ) {
return "李四";
}
return "张三";
}
}
(4)postman请求该URL
GET请求: http://192.168.11.7:27100/text/query/1
返回结果:
方法执行前
即将调用该方法:query
方法执行后
入参:[1],调用方法名称:query
调用方法之后
调用方法并正常返回后执行