大数跨境
0
0

优雅!Spring AOP + 自定义注解,动态业务规则校验

优雅!Spring AOP + 自定义注解,动态业务规则校验 Spring全家桶实战案例
2025-08-06
0
导读:优雅!Spring AOP + 自定义注解,动态业务规则校验
Spring Boot 3实战案例锦集PDF电子书已更新至130篇!

🎉🎉《Spring Boot实战案例合集》目前已更新153个案例,我们将持续不断的更新。文末有电子书目录。

💪💪永久更新承诺

我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务

💌💌如何获取
订阅我们的合集点我订阅,并通过私信联系我们,我们将第一时间将电子书发送给您。

→ 现在就订阅合集

环境:SpringBoot3.4.2



1. 简介

在复杂业务系统开发中,校验逻辑与业务代码混杂的问题普遍存在。大量 if-else 判断导致代码臃肿、可读性差,且规则变更需频繁修改业务代码,违背开闭原则。尤其在电商、金融等领域,订单创建、交易处理等场景涉及时间限制、库存状态、用户权限等多维度校验,传统硬编码方式易引发漏判、误判,且难以复用校验逻辑。

本篇文章将基于 AOP 实现动态业务规则校验,通过将校验逻辑抽离为独立规则组件,实现业务与校验的解耦。借助注解灵活组合规则,支持快速失败与全量校验模式,可动态适配规则变化,大幅提升代码可维护性与系统扩展性,成为复杂业务场景的高效解决方案。

如下最终效果:

@BusinessValidation(rules = {     OrderAmountValidation.class    OrderAddressValidation.class }, failFast = false)public void createOrder(Order order) {  System.err.println("订单创建成功") ;}

输出结果

2.实战案例

2.1 自定义注解

@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface BusinessValidation {
  /**需要执行的校验规则类数组*/  Class<? extends ValidationRule>[] rules() ;  /**是否快速失败(遇到第一个校验失败就抛出异常)*/  boolean failFast() default true;  /**校验失败时是否抛出异常*/  boolean throwException() default true;  /**校验失败时的错误消息模板*/  String message() default "规则校验失败";}

2.2 规则接口定义

/**业务校验规则接口,所有具体校验规则需实现此接口*/public interface ValidationRule {  ValidationResult validate(Object target, Method method, Object[] args);}// 校验结果public class ValidationResult {  /**校验是否通过*/  private final boolean valid ;  /**错误消息*/  private final String message ;  private ValidationResult(boolean valid, String message) {    this.valid = valid;    this.message = message;  }  /**创建校验通过的结果*/  public static ValidationResult valid() {    return new ValidationResult(truenull);  }  /**创建校验失败的结果*/  public static ValidationResult invalid(String message) {    return new ValidationResult(false, message);  }  public boolean isValid() {    return valid;  }  public String getMessage() {    return message;  }}

接下来,我们先定义几个不同规则的实现

// 校验订单金额@Componentpublic class OrderAmountValidation implements ValidationRule {  // 最大订单金额限制  private static final BigDecimal MAX_AMOUNT = new BigDecimal("100000") ;  @Override  public ValidationResult validate(Object target, Method method, Object[] args) {    // 假设第1个参数Order对象(实际可以考虑通过注解方式?)    BigDecimal amount = ((Order) args[0]).getAmount() ;    if (amount.compareTo(BigDecimal.ZERO) <= 0) {      return ValidationResult.invalid("订单金额必须大于0");    }    if (amount.compareTo(MAX_AMOUNT) > 0) {      return ValidationResult.invalid("订单金额超过最大限制: " + MAX_AMOUNT);    }    return ValidationResult.valid() ;  }}// 校验订单邮寄地址@Componentpublic class OrderAddressValidation implements ValidationRule {  private static final Set<StringNO_SUPPORT = Set.of("新疆""西藏") ;  @Override  public ValidationResult validate(Object target, Method method, Object[] args) {    // 假设第1个参数Order对象(实际可以考虑通过注解方式?)    String address = ((Order) args[0]).getAddress() ;    if (NO_SUPPORT.contains(address)) {      return ValidationResult.invalid(String.format("【%s】不支持的邮寄地址", address));    }    return ValidationResult.valid() ;  }}

2.3 规则校验切面

@Aspect@Componentpublic class BusinessValidationAspect implements ApplicationContextAware {  private ApplicationContext context;  @Around("@annotation(validation)")  public Object validateBusinessRules(ProceedingJoinPoint pjp, BusinessValidation validation)      throws Throwable {    Object target = pjp.getTarget() ;    Method method = ((MethodSignature) pjp.getSignature()).getMethod();    Object[] args = pjp.getArgs();    // 1.获取需要执行的校验规则类    Class<? extends ValidationRule>[] ruleClasses = validation.rules();    List<ValidationRule> rules = new ArrayList<>();    // 2.获取所有的校验规则(如果不是bean对象则进行创建)    for (Class<? extends ValidationRule> clazz : ruleClasses) {      try {        ValidationRule rule = context.getBean(clazz) ;        rules.add(rule) ;      } catch (Exception e) {        // 创建实例        Objenesis obj = new ObjenesisStd() ;        ValidationRule rule = obj.newInstance(clazz) ;        rules.add(rule) ;      }    }    List<String> errors = new ArrayList<>() ;    // 3.执行所有校验规则    for (ValidationRule rule : rules) {      ValidationResult result = rule.validate(target, method, args) ;      if (!result.isValid()) {        // 校验失败,根据注解配置决定抛出异常或继续执行        if (validation.failFast()) {          errors.add(result.getMessage()) ;          break ;        } else {          // 非快速失败模式,收集所有错误信息          errors.add(result.getMessage()) ;        }      }    }
    // 4.错误信息处理    if (!errors.isEmpty() && validation.throwException()) {      throw new BusinessValidationException(errors) ;    } else {      System.err.println(errors) ;    }    // 5.继续向下执行    return pjp.proceed();  }  @Override  public void setApplicationContext(ApplicationContext context) throws BeansException {    this.context = context ;  }}

在该切面中,我们通过 Objenesis 创建规则实例对象,你在应用此方法时,你需要了解下它创建对象的规则,详细请查看下面文章:

避坑!为了性能Spring挖了一个大坑

2.4 异常处理

@RestControllerAdvicepublic class GlobalExceptionHandler {  @ExceptionHandler()  public ResponseEntity<?> businessValidationException(BusinessValidationException e) {    return ResponseEntity.ok(e.getErrors()) ;  }}// 异常对象public class BusinessValidationException extends RuntimeException {  private List<String> errors = new ArrayList<>() ;  public BusinessValidationException(List<String> errors) {    super("") ;    this.errors = errors ;  }}

2.5 测试

@Servicepublic class OrderService {  @BusinessValidation(rules = {       OrderAmountValidation.class      OrderAddressValidation.class   }, failFast = false)  public void createOrder(Order order) {    System.err.println("订单创建成功") ;  }}

Controller接口

private final OrderService orderService ;public OrderController(OrderService orderService) {  this.orderService = orderService;}@PostMapping("/create")public ResponseEntity<?> create(@RequestBody Order order) {  this.orderService.createOrder(order) ;  return ResponseEntity.ok(order) ;}

以上就完成了基于注解的动态规则校验。


以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏

推荐文章

分布式事务解决神器Seata!TCC模式

Spring Boot + JobRunr 后台任务执行神器,太强大了

高级开发!Spring Boot 零侵入动态功能扩展

强大!借助Spring Boot内置动态刷新功能,实时更新组件

性能优化!3种方案优化Controller接口调用,性能提升N倍

重磅!Spring Cloud Gateway 全面支持 Servlet 技术栈,简单多了

性能优化!7个策略,让Spring Boot 处理每秒百万请求

Spring Boot自定义注解+参数解析器,构建灵活的安全认证机制

优雅!SpringBoot详细记录SQL执行耗时情况

必学!Spring Boot结合MDC全方位的日志跟踪(支持跨线程)

考察你对 Spring 基本功掌握能力

【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读195
粉丝0
内容832