Java切入点案例如何配置拦截

wen java案例 29

深度解析Java切入点配置:从案例到实战的拦截机制全掌握

目录导读

  1. 切入点概念与核心角色 – 什么是切入点?它在AOP中扮演什么角色?
  2. 基于注解的拦截配置 – 用@Around实现方法耗时监控
  3. 切入点表达式详解 – execution()、within()、@annotation()等通配符实战
  4. 多个切入点的组合与优先级 – 拦截顺序与@Order的微妙关系
  5. 常见问答 – 拦截失败、表达式写错、性能问题怎么办?

切入点概念与核心角色

在Java的面向切面编程(AOP)中,切入点(Pointcut) 是决定哪些连接点(JoinPoint)被拦截的“过滤规则”,简单说,它告诉Spring:“当执行哪些方法时,请执行我的通知(Advice)”,你想拦截所有Service层方法进行日志记录,切入点就是定义“所有com.example.service包下以*ServiceImpl结尾的类中的任意方法”的表达式。

Java切入点案例如何配置拦截

核心疑问:为什么需要切入点?直接写拦截逻辑不行吗?
答案在于关注点分离,通过切入点配置,你可以将日志、权限、事务等横切逻辑与业务代码解耦,修改拦截规则时只需调整切入点表达式,无需改动业务类。


案例一:基于注解的拦截配置——方法耗时监控

场景:需要监控所有标注了@MonitorTime注解的方法执行耗时。

步骤1:自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MonitorTime {}
步骤2:编写切面类
@Aspect
@Component
public class TimeMonitorAspect {
    @Around("@annotation(com.example.annotation.MonitorTime)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long elapsedTime = System.currentTimeMillis() - start;
        System.out.println(joinPoint.getSignature() + " 耗时:" + elapsedTime + "ms");
        return result;
    }
}
步骤3:在业务方法标注注解
@Service
public class UserService {
    @MonitorTime
    public User findUserById(Long id) {
        // 模拟耗时操作
        Thread.sleep(200);
        return new User(id, "Alice");
    }
}

关键点

  • @annotation(com.example.annotation.MonitorTime) 是切入点表达式,只拦截标注了该注解的方法。
  • 若想拦截类级别注解,可改用 @within(com.example.annotation.MonitorTime)

案例二:切入点表达式详解——从execution到通配符

通用格式execution([修饰符] 返回类型 包名.类名.方法名(参数) throws 异常)

常用表达式示例
表达式 作用
execution(* com.example.service.*.*(..)) 拦截service包下所有类的所有方法
execution(public * *(..)) 拦截所有公有方法
execution(* com.example..*.*(..)) 代表当前包及其子包
within(com.example.service.*) 匹配指定包下的所有方法(比execution更简洁)
@annotation(org.springframework.web.bind.annotation.GetMapping) 匹配标注了@GetMapping的方法
实际案例:只拦截返回值为String的方法
@Around("execution(String com.example.service.*.*(..))")
public Object aroundStringMethods(ProceedingJoinPoint pjp) throws Throwable {
    // 仅对String返回的方法生效
    return pjp.proceed();
}

常见踩坑

  • 包名中只能匹配一级包,才匹配多级。
  • 参数表示任意参数,(String, *)表示第一个参数为String,第二个任意。
  • 若切入点匹配不到任何方法,先检查AOP是否启用(@EnableAspectJAutoProxy)。

案例三:多个切入点的组合与优先级

当系统存在多个切面时,配置顺序直接决定执行链路。

情景:一个方法同时被“日志切面”和“权限切面”拦截,如何让权限检查先执行?

解决方案:使用@Order注解
@Aspect
@Component
@Order(1)  // 值越小优先级越高,越先执行
public class PermissionAspect {
    @Around("execution(* com.example.controller.*.*(..))")
    public Object checkPermission(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("权限检查中...");
        return pjp.proceed();
    }
}
@Aspect
@Component
@Order(2)
public class LogAspect {
    @Around("execution(* com.example.controller.*.*(..))")
    public Object log(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("日志记录前");
        Object result = pjp.proceed();
        System.out.println("日志记录后");
        return result;
    }
}

执行顺序
权限切面@Around中的proceed()调用日志切面,日志切面执行前置逻辑→业务方法→日志后置逻辑→权限后置逻辑(除非有异常)。

注意

  • 若未指定@Order,Spring会按切面类的字母顺序执行,这点极易导致BUG。
  • 在同一App中,建议所有切面都显式设置顺序。

常见问答

Q1:为什么我的切入点配置了,但方法没有被拦截?

  • 检查是否使用了@EnableAspectJAutoProxy(Spring Boot中默认开启,但若使用XML配置需手动声明)。
  • 确认切入点表达式包名、类名、方法签名书写完全正确。
  • 若使用@around,确认在通知中调用了proceed()方法。

Q2:execution和@annotation的区别?

  • execution基于方法签名匹配(包、类、方法名、参数)。
  • @annotation基于注解匹配,更灵活,尤其适合标记式拦截。

Q3:如何在一个切面中定义多个切入点?

@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}
@Pointcut("@annotation(com.example.annotation.MonitorTime)")
public void monitorMethods() {}
@Before("serviceLayer() && monitorMethods()")
public void combinedAdvice() {
    // 拦截同时满足两个条件的连接点
}

使用&&、、运算符组合切入点。

Q4:拦截后性能下降明显怎么办?

  • 缩小切入点范围,避免拦截高频调用方法。
  • 对通知方法进行轻量化处理,避免在拦截逻辑中执行数据库查询或复杂计算。
  • 使用@Around时,确保proceed()调用正确且没有多余的try-catch。

SEO优化要点(必应/谷歌)含核心关键词“Java切入点配置”“拦截案例”等。 埋词:自然分布“Spring AOP”“execution表达式”“@Around”“@Order”等术语。

  • 案例驱动:搜索引擎喜欢能解决实际问题的步骤式内容。
  • 问答结构:通过常见问答提高页面互动率。
  • 内链与外链(示例):可引用Spring官方文档句“A pointcut determines join points at which advice should be applied.”。

抱歉,评论功能暂时关闭!