目录
概述:
AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,主要用于将共性功能从具体的业务逻辑中分离出来,实现松耦合的代码设计。其作用是在不修改原始代码的情况下,对现有方法进行增强,广泛应用于日志记录、安全检查、事务管理等场景。
AOP的核心概念
在AOP中,有几个核心的概念(25-AOP工作流程)(31-AOP开发总结):
- 连接点(JoinPoint): 程序执行过程中可被拦截的点,如方法调用或异常抛出。
@Before("execution(* com.itheima.service.*.*(..))")
public void beforeMethod(JoinPoint joinPoint) {
System.out.println("方法名:" + joinPoint.getSignature().getName());
}
切入点(Pointcut): 用来定义在哪些连接点上执行通知。可以使用表达式来选择目标方法(26-AOP切入点表达式)。
例如,execution(* com.itheima.dao.BookDao.save())匹配BookDao中的save方法。通知(Advice): 指定在某个切入点处执行的增强操作。通知可以在方法执行前(前置通知)、后(后置通知)、返回后(返回通知)、抛出异常后(异常通知)或者环绕执行(27-AOP通知类型)(31-AOP开发总结)。
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object result = pjp.proceed(); // 调用原始方法
long end = System.currentTimeMillis();
System.out.println("方法执行时间:" + (end - start) + "ms");
return result;
}
- 切面(Aspect): 切面是通知与切入点的结合,切面定义了增强逻辑如何应用到具体的方法中。
AOP的实现方式
在Spring中,AOP的实现主要有两种方式:基于XML的配置方式 和基于注解的方式。目前使用较多的是注解方式。以下是一个基于注解的简单AOP实现步骤(24-AOP入门案例):
1. 定义DAO接口和实现类
public interface BookDao {
void save();
void update();
}
@Repository
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("执行save方法");
}
public void update() {
System.out.println("执行update方法");
}
}
2. 定义通知类
通知类中定义了在方法执行前后的增强操作。例如,下面的MyAdvice类定义了在update方法执行前记录时间(27-AOP通知类型)(28-案例:测量业务层接口万次执行效率)。
@Aspect
@Component
public class MyAdvice {
@Pointcut("execution(void com.itheima.dao.BookDao.update())")
private void pt(){}
@Before("pt()")
public void before() {
System.out.println("执行前时间:" + System.currentTimeMillis());
}
}
3. 开启AOP注解驱动
在Spring配置类中,使用@EnableAspectJAutoProxy注解来开启AOP注解的自动代理(24-AOP入门案例):
@Configuration
@ComponentScan("com.itheima")
@EnableAspectJAutoProxy
public class SpringConfig {}
切入点表达式
切入点表达式是AOP中非常关键的一部分,它描述了要增强的方法,常见的切入点表达式格式为:
execution(访问修饰符 返回值类型 包名.类名.方法名(参数))
例如
execution(* com.itheima.service.UserService.findById(..))
该表达式匹配UserService中名为findById的方法。
通配符的使用:
*:匹配任意符号。例如,execution(* *..*Service.*(..))匹配所有Service类中的任意方法。..:匹配多个连续的任意符号。例如,execution(* com.itheima..*.save(..))匹配com.itheima包下所有类中的save方法。
AOP通知类型
根据增强操作执行的时机,通知可以分为以下几种类型(27-AOP通知类型):
- 前置通知(@Before): 在目标方法执行之前调用通知。
2.
@Before("pt()")
public void beforeAdvice() {
System.out.println("前置通知执行...");
}
- 后置通知(@After): 在目标方法执行之后调用通知。
4.
@After("pt()")
public void afterAdvice() {
System.out.println("后置通知执行...");
}
环绕通知(@Around): 可以在方法执行前后都添加增强逻辑。
@Around("pt()") public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable { System.out.println("环绕通知执行前..."); Object ret = pjp.proceed(); // 执行目标方法 System.out.println("环绕通知执行后..."); return ret; }返回后通知(@AfterReturning): 在方法正常返回后执行。
@AfterReturning(pointcut = "pt()", returning = "retVal") public void afterReturningAdvice(Object retVal) { System.out.println("返回后通知执行... 返回值: " + retVal); }异常通知(@AfterThrowing): 当方法抛出异常时调用。
@AfterThrowing(pointcut = "pt()", throwing = "ex") public void afterThrowingAdvice(Exception ex) { System.out.println("异常通知执行... 异常信息: " + ex.getMessage()); }案例分析:测量业务层接口的执行效率
在实际开发中,AOP被广泛应用于日志记录和性能监控。在以下案例中,通过环绕通知,我们可以测量业务接口执行的时间
7.@Around("execution(* com.itheima.service.*.*(..))") public Object measureExecutionTime(ProceedingJoinPoint pjp) throws Throwable { long start = System.currentTimeMillis(); Object result = pjp.proceed(); // 执行目标方法 long end = System.currentTimeMillis(); System.out.println("方法执行时间:" + (end - start) + "ms"); return result; }结论
通过AOP,可以轻松地将共性功能与业务逻辑分离,减少代码重复,提高代码的可维护性。AOP的核心在于定义好切入点,并使用合适的通知来增强方法。
原文链接: https://blog.csdn.net/2302_80084329/article/details/142268031