本文目录导读:

我来详细介绍Spring AOP切面表达式的各类拦截方式。
切面表达式基本语法
execution([修饰符] 返回类型 [包名.类名.]方法名(参数) [throws 异常])
常用拦截示例
拦截所有公共方法
@Before("execution(public * *(..))")
public void beforePublicMethod() {
// 拦截所有public方法
}
拦截指定包下所有方法
// 拦截com.example.service包及其子包下的所有方法
@Before("execution(* com.example.service..*.*(..))")
public void beforeServiceMethod() {
// .. 表示包及其子包
}
拦截指定类所有方法
// 拦截UserServiceImpl类的所有方法
@Before("execution(* com.example.service.impl.UserServiceImpl.*(..))")
public void beforeUserServiceImpl() {
}
拦截特定方法名
// 拦截以save开头的方法
@Before("execution(* com.example.service.*.save*(..))")
public void beforeSaveMethod() {
}
// 拦截findById方法
@Before("execution(* com.example.service.*.findById(Long))")
public void beforeFindById() {
}
拦截带特定参数的方法
// 拦截第一个参数是String类型的方法
@Before("execution(* com.example.service.*.*(String, ..))")
public void beforeMethodWithStringParam() {
}
// 拦截无参方法
@Before("execution(* com.example.service.*.*())")
public void beforeNoParamMethod() {
}
// 拦截只有一个参数的方法
@Before("execution(* com.example.service.*.*(*))")
public void beforeOneParamMethod() {
}
根据注解拦截
// 拦截自定义注解@Log的方法
@Before("@annotation(com.example.annotation.Log)")
public void beforeLogAnnotation() {
}
// 拦截类上有@Controller注解的方法
@Before("@within(org.springframework.stereotype.Controller)")
public void beforeControllerMethod() {
}
// 拦截参数上有特定注解的方法
@Before("@args(com.example.annotation.Valid)")
public void beforeValidParam() {
}
复杂组合表达式
使用逻辑运算符
// 两个条件同时满足 (and可以用&&代替)
@Before("execution(* com.example.service.*.*(..)) && @annotation(com.example.annotation.Log)")
public void beforeServiceAndLog() {
}
// 满足任一条件
@Before("execution(* com.example.service.*.save*(..)) || execution(* com.example.service.*.update*(..))")
public void beforeSaveOrUpdate() {
}
// 排除某些方法
@Before("execution(* com.example.service.*.*(..)) && !execution(* com.example.service.*.find*(..))")
public void beforeNotFind() {
}
使用within限定类范围
// 拦截@Service注解的类
@Before("within(@org.springframework.stereotype.Service *)")
public void beforeServiceAnnotation() {
}
// 拦截指定包下的所有类
@Before("within(com.example.service.*)")
public void beforeServicePackage() {
}
// 拦截接口实现类
@Before("within(com.example.service.UserService+)")
public void beforeUserServiceImple() {
}
this和target的区别
// target: 匹配目标对象(被代理对象)
@Before("target(com.example.service.UserService)")
public void beforeTarget() {
}
// this: 匹配代理对象
@Before("this(com.example.service.UserService)")
public void beforeThis() {
}
// 区别:当使用CGLIB代理时,this和target可能不同
实战案例
统一日志切面
@Component
@Aspect
public class LogAspect {
// 定义通用切点
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethod() {}
@Pointcut("@annotation(com.example.annotation.Log)")
public void logAnnotation() {}
// 组合使用
@Before("serviceMethod() && logAnnotation()")
public void beforeLog(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("执行方法: " + methodName);
}
}
性能监控切面
@Component
@Aspect
public class PerformanceAspect {
@Around("execution(* com.example.service.*.*(..)) && !execution(* com.example.service.*.get*(..))")
public Object measurePerformance(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long end = System.currentTimeMillis();
System.out.println(joinPoint.getSignature() + " 执行时间: " + (end - start) + "ms");
return result;
}
}
权限校验切面
@Component
@Aspect
@Order(1) // 控制切面执行顺序
public class AuthAspect {
@Around("@annotation(com.example.annotation.RequireRole)")
public Object checkRole(ProceedingJoinPoint joinPoint, RequireRole requireRole) throws Throwable {
String[] roles = requireRole.value();
// 获取当前用户角色
String currentRole = getCurrentUserRole();
if (Arrays.asList(roles).contains(currentRole)) {
return joinPoint.proceed();
}
throw new SecurityException("权限不足");
}
}
常见表达式速查表
| 表达式 | 含义 |
|---|---|
execution(* *(..)) |
所有方法 |
execution(public * *(..)) |
所有public方法 |
execution(* com.example..*.*(..)) |
指定包及其子包所有方法 |
bean(userService) |
指定bean名称 |
@annotation(org.springframework.web.bind.annotation.GetMapping) |
有指定注解的方法 |
within(com.example.service.*) |
指定包内的所有类 |
args(String, ..) |
第一个参数为String |
this(com.example.service.UserService) |
代理对象是UserService类型 |
target(com.example.service.UserService) |
目标对象是UserService类型 |
注意事项
- 性能影响:过于复杂的表达式可能影响性能
- 顺序问题:多个切面使用
@Order控制顺序 - 通配符使用:匹配任意字符,匹配任意参数或包路径
- 使用Pointcut:建议将通用表达式定义为
@Pointcut复用
这样就可以根据实际需求灵活配置AOP切面表达式了!