深入理解AOP(面向切面编程)及其应用

目录

AOP的核心概念

AOP的实现方式

1. 定义DAO接口和实现类

2. 定义通知类

3. 开启AOP注解驱动

切入点表达式

通配符的使用:

AOP通知类型

案例分析:测量业务层接口的执行效率

结论


概述:
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通知类型):

  1. 前置通知(@Before): 在目标方法执行之前调用通知。

  2. @Before("pt()")
    public void beforeAdvice() {
        System.out.println("前置通知执行...");
    }
    

  3. 后置通知(@After): 在目标方法执行之后调用通知。

  4. @After("pt()")
    public void afterAdvice() {
        System.out.println("后置通知执行...");
    }
    

  5. 环绕通知(@Around): 可以在方法执行前后都添加增强逻辑。

    @Around("pt()")
    public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕通知执行前...");
        Object ret = pjp.proceed();  // 执行目标方法
        System.out.println("环绕通知执行后...");
        return ret;
    }
    

  6. 返回后通知(@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的核心在于定义好切入点,并使用合适的通知来增强方法。

你可能感兴趣的:(java,开发语言,spring)