AOP
约 536 字大约 2 分钟
2024-12-25
面向切面编程,
编写切面
@Around("@annotation(cn.lut.imserver.aop.Monitored) || @within(cn.lut.imserver.aop.Monitored)")
标记切入点,@annotation
标记表示拦截 Monitored 注解的方法,@within
标记表示该注解类中的所有方法
对于使用被切面标记的注释的 bean,其在初始化时会被创建代理类,此后该 bean 被调用时都会经过切面进行处理
ProceedingJoinPoint
代理对象被调用时会创建该类,构建拦截器链,将该对象交给切面进行处理
@Slf4j
@Aspect
@Component
public class ControllerLoggingAspect {
@Around("@annotation(cn.lut.imserver.aop.Monitored) || @within(cn.lut.imserver.aop.Monitored)")
public Object logAround(ProceedingJoinPoint pjp) {
MethodSignature sig = (MethodSignature) pjp.getSignature();
String className = sig.getDeclaringType().getSimpleName();
String methodName = sig.getName();
String method = className + "." + methodName;
log.info("Invoke method {}", method);
long start = System.currentTimeMillis();
try {
return pjp.proceed();
} catch (Throwable e) {
throw new RuntimeException(e);
} finally {
long end = System.currentTimeMillis();
log.info("Method {} end with {} ms", method, end - start);
}
}
}
概念
切面
即通知
+切入点
,在什么地方 (切入点),执行什么逻辑 (通知)
连接点
程序中可以被拦截的执行点
切入点
匹配某些连接点的表达式,用于从连接点中选出需要增强的的点
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethod() {}
匹配com.example.service
包下的所有所有的方法,讲这些方法作为需要增强的点
execution()
:方法执行切入点- 第一个
*
:表示任意返回类型 com.example.service
:包路径包路径.*
:该包下的任意类包路径.*.*
:类中的任意方法(..)
:任意参数列表
通知
对于匹配的连接点执行的增强逻辑
前置通知
在方法执行前
@Before("execution(* cn.codeartist.spring.aop.advice.*.*(..))")
public void doBefore() {
// 自定义逻辑
}
环绕通知
获取切入点(对代理类的控制),定义方法执行前后的逻辑,如果不执行joinPoint.proceed()
,那么该方法将不会执行
@Around("execution(* cn.codeartist.spring.aop.advice.*.*(..))")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
// 方法执行前逻辑
Object retVal = joinPoint.proceed();
// 方法执行后逻辑
return retVal;
}
后置通知
方法正常返回后
@AfterReturning("execution(* cn.codeartist.spring.aop.advice.*.*(..))")
public void doAfterReturning() {
// 自定义逻辑
}
工作原理
为被切入点规则匹配的连接点创建代理类(JDK 或 CGLIB),这些类中的方法被调用时,