一、AOP介绍
AOP(面向切面编程)是一种编程思想,底层逻辑是动态代理。什么是动态代理呢?动态代理就是不改变源码的情况下,对目标方法进行增强。传统的动态代理太过繁琐,因此SpringAOP对其进行了一系列简化,使得原本繁琐的代码变得精简,同时使用也更加灵活。
二、AOP使用案例
在开发过程中,日志是必不可少的。以前的日志代码需要在每个方法上都添加相同的一段代码,这导致代码复用性很低。
SpringAOP将这都进行了优化,以下是二者代码的区别:
传统的日志功能:
public class MyClass {
private static final Logger logger = LogManager.getLogger(MyClass.class);
public void doSomethingWithLogging(String input) {
// 记录方法开始的日志
logger.info("Method 'doSomethingWithLogging' started with input: {}", input);
try {// 执行具体的业务逻辑
// ...
// 记录方法成功结束的日志
logger.info("Method 'doSomethingWithLogging' successfully completed");
} catch (Exception e) {
// 记录方法异常的日志
logger.error("An error occurred in method 'doSomethingWithLogging'", e);
}
}
}
SpringAOP日志功能:
@Aspect
@Component
public class LoggingAspect {
private Log logger = LogFactory.getLog(this.getClass());
@Before("execution(* com.example.MyService.*(..))") //前置通知
public void logBefore(JoinPoint joinPoint) {
logger.info("Method " + joinPoint.getSignature().getName() + " is about to be executed"); }
@AfterReturning(pointcut = "execution(* com.example.MyService.*(..))", returning = "result")//运行成功后通知
public void logAfterReturning(JoinPoint joinPoint, Object result) {
logger.info("Method " + joinPoint.getSignature().getName() + " executed successfully"); }
@AfterThrowing(pointcut = "execution(* com.example.MyService.*(..))", throwing = "exception")//运行异常通知
public void logAfterThrowing(JoinPoint joinPoint, Throwable exception) {
logger.error("Exception thrown from method " + joinPoint.getSignature().getName() + ": " + exception.getMessage());
}
}
@Service
public class MyService {
public void doSomething() {
// 具体业务逻辑
}
}
在这个示例中,LoggingAspect类是一个切面,它定义了在MyService类中的方法执行前、执行后(成功返回)和执行后(抛出异常)分别记录日志的逻辑。当MyService类中的方法被调用时,LoggingAspect中对应的通知将会被触发,实现日志记录的功能。
三、SpringAOP
简介
SpringAOP是对AOP思想的一种实现,Spring底层同时支持jdk动态代理(基于接口)和cglib动态代理(基于继承)。Spring会根据被代理的类是否有接口自动选择代理方式
如果有接口,就采用jdk动态代理
如果没接口,就采用cglib的方式
核心概念
-
目标对象(Target)
被代理的对象 -
连接点(JoinPoint)
目标对象中的所有方法 -
切入点(PointCut)
目标对象中要真正进行功能增强的方法切入点表达式:
1、指定匹配切入点的规则:*用于返回值,包名,方法名,表示任意,占一个位置,.. 表示0-n的任意数量
2、execution表达式匹配
@Pointcut("execution(* com.example.service.*.*(..))")
private void serviceMethods() {
}
3、@annotation注解匹配
自定义一个注解,把它标记在对应的方法上,通过切点表达式去识别这个注解
@Pointcut("@annotation(com.example.annotation.Loggable)")
private void loggableMethods() {
}
* **增强 (Advice 通知)** 一个具体增强功能(增强对象 增强方法)
前置通知(before):增强方法在切点运行之前执行
返回通知(after-returning):增强方法在切点正常完成后执行的通知,不包括抛出异常的情况
异常通知(after-throwing):增强方法在某切点抛出异常退出时执行的通知
后置通知(after):增强方法在某切点退出的时候执行的通知(不论是正常返回还是异常退出)
环绕通知(around):一种特殊的通知,他允许以编码的形式实现上面的四大通知
- 切面 (Aspect)
切面是一种描述,描述的是: 哪个增强方法加入到了哪个切点的什么位置
总之切面可以理解为 切入点和增强的结合
@Aspect
@Component
public class LoggingAspect {
@Around("execution(* com.example.MyService.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
// 在方法执行前记录日志
System.out.println("Before method execution: " + joinPoint.getSignature().getName());
// 执行目标方法
Object result = joinPoint.proceed();
// 在方法执行后记录日志
System.out.println("After method execution: " + joinPoint.getSignature().getName());
return result;
}
}
在这个示例中,LoggingAspect类是一个切面,它定义了一个环绕通知。在logAround方法中,我们可以在目标方法执行前和执行后分别记录日志,并通过调用joinPoint.proceed()来执行目标方法。
然后,在你的Service类中,定义一个方法,该方法将被切面所通知:
@Service public class MyService {
public void doSomething() {
// 具体业务逻辑
}
}
标签:通知,joinPoint,MyService,SpringAOP,日志,方法,public
From: https://www.cnblogs.com/w123-/p/17991223