Aspect Oriented Programming(AOP)从某种意义上说是对 OOP 的补充,因为它还提供了模块化的功能。但是模块化的关键单元是方面而不是类。

AOP 将程序逻辑分为不同的部分(称为关注点)。它用于通过 跨领域关注点来提高模块化

使用

提供声明式企业服务,例如声明式事务管理。
它允许用户实现自定义 aspects。

通过 “自定义注解 + AOP” 的组合,可将校验逻辑与业务代码解耦:

示例:校验时使用

  1. 自定义注解:作为 “标记”,标识需要进行校验的方法或参数(如 @NeedValidation)。
1
2
3
4
5
6
7
8
9
10
import java.lang.annotation.*;

// 注解可用于方法上
@Target(ElementType.METHOD)
// 注解在运行时生效(AOP需要在运行时解析)
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedValidation {
// 可添加属性,例如指定校验分组
String[] groups() default {};
}
  1. AOP 切面:拦截被该注解标记的方法,在方法执行前调用 ValidationUtils 中的校验逻辑。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

// 切面类:将注解与校验逻辑关联
@Aspect
@Component // 纳入Spring容器(若用Spring框架)
public class ValidationAspect {

// 切入点:拦截所有被@NeedValidation注解标记的方法
@Pointcut("@annotation(needValidation)")
public void validationPointcut(NeedValidation needValidation) {}

// 前置通知:在目标方法执行前执行校验
@Before("validationPointcut(needValidation)")
public void doValidation(JoinPoint joinPoint, NeedValidation needValidation) {
// 获取目标方法的参数
Object[] args = joinPoint.getArgs();
// 获取目标方法名(用于针对性校验)
String methodName = joinPoint.getSignature().getName();

// 根据方法名或参数类型执行不同的校验逻辑
switch (methodName) {
case "getUserById":
// 假设第一个参数是用户ID
Long userId = (Long) args[0];
ValidationUtils.validateUserId(userId);
break;
case "createUser":
// 假设第一个参数是用户名
String username = (String) args[0];
ValidationUtils.validateString(username, "用户名");
break;
// 其他方法的校验规则...
default:
throw new IllegalArgumentException("未定义方法 " + methodName + " 的校验规则");
}
}
}
  1. ValidationUtils:封装具体的校验规则(如参数非空、格式校验等)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class ValidationUtils {
/**
* 示例:校验用户ID是否合法(非空且为正数)
*/
public static void validateUserId(Long userId) {
if (userId == null) {
throw new IllegalArgumentException("用户ID不能为空");
}
if (userId <= 0) {
throw new IllegalArgumentException("用户ID必须为正数");
}
}

/**
* 示例:校验字符串参数是否非空且不为空串
*/
public static void validateString(String param, String paramName) {
if (param == null || param.trim().isEmpty()) {
throw new IllegalArgumentException(paramName + "不能为空");
}
}

// 可根据业务需求添加更多校验方法
}
  1. 在业务中使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import org.springframework.stereotype.Service;

@Service
public class UserService {

// 只需添加@NeedValidation注解,即可自动触发校验
@NeedValidation
public String getUserById(Long userId) {
// 业务逻辑:查询用户
return "用户信息:" + userId;
}

@NeedValidation
public void createUser(String username) {
// 业务逻辑:创建用户
System.out.println("创建用户:" + username);
}
}

自定义注解本身只是一个 “标记”,无法主动执行校验逻辑。AOP 通过 “切面” 拦截被注解标记的方法,在方法执行前后插入校验代码,实现 “注解即校验” 的效果。