当前位置: 首页 > news >正文

自定义注解实现服务分处理-策略模式

路由:请求标识→匹配 Service→调用 process 方法

通过自定义注解 @BusinessServiceMapping 标记具体业务 Service,注解值(如 DC 代表客户、ORD 代表订单)与请求参数中的业务标识关联;再通过 Spring 容器扫描 + 策略模式,实现 “请求标识→匹配 Service→调用 process 方法” 的自动路由,避免硬编码分支判断。

根据条件动态选择执行,解耦 “选择逻辑” 和 “业务实现”

自定义注解:@BusinessServiceMapping(标记业务 Service)

import org.springframework.stereotype.Component;
import java.lang.annotation.*;/*** 自定义业务Service映射注解:标记Service对应的业务标识(如DC=客户、ORD=订单)*/
@Target({ElementType.TYPE}) // 仅用于类(Service实现类)
@Retention(RetentionPolicy.RUNTIME) // 运行时保留,便于反射获取
@Documented
@Component // 让Spring自动扫描该注解标记的类
public @interface BusinessServiceMapping {/*** 业务标识(如DC=客户、ORD=订单),支持多标识(如一个Service处理多个相关业务)*/String[] value();/*** 业务描述(可选,用于文档说明)*/String desc() default "";
}

2. 业务 Service 接口:BusinessProcessService(定义统一方法)

import com.yourproject.dto.BusinessRequestDTO;
import com.yourproject.dto.BusinessResponseDTO;/*** 业务Service统一接口:所有业务Service需实现此接口*/
public interface BusinessProcessService {/*** 统一业务处理方法* @param requestDTO 业务请求参数(封装请求标识、业务数据等)* @return 业务处理结果*/BusinessResponseDTO process(BusinessRequestDTO requestDTO);/*** 获取当前Service支持的业务标识(与@BusinessServiceMapping的value对应,便于校验)*/String[] getSupportBusinessCodes();
}

3. 业务请求 / 响应 DTO:封装参数与结果

// 业务请求DTO:请求需携带业务标识(如dc、ord)
public class BusinessRequestDTO {/*** 业务标识(与@BusinessServiceMapping的value对应,如DC=客户、ORD=订单)*/private String businessCode;/*** 具体业务数据(JSON字符串,根据业务类型解析)*/private String businessData;// getter + setter
}// 业务响应DTO:统一返回格式
public class BusinessResponseDTO {/*** 处理状态(SUCCESS/FAIL)*/private String status;/*** 响应消息*/private String message;/*** 业务结果数据(JSON字符串)*/private String resultData;// 静态工厂方法:简化创建public static BusinessResponseDTO success(String message, String resultData) {BusinessResponseDTO dto = new BusinessResponseDTO();dto.setStatus("SUCCESS");dto.setMessage(message);dto.setResultData(resultData);return dto;}public static BusinessResponseDTO fail(String message) {BusinessResponseDTO dto = new BusinessResponseDTO();dto.setStatus("FAIL");dto.setMessage(message);return dto;}// getter + setter
}

4. 业务 Service 实现类(示例:客户 Service + 订单 Service)

// 示例1:客户业务Service(标识DC)
@BusinessServiceMapping(value = "DC", // 业务标识:DC=客户desc = "客户相关业务处理(新增/编辑/查询客户)"
)
public class CustomerBusinessService implements BusinessProcessService {@Overridepublic BusinessResponseDTO process(BusinessRequestDTO requestDTO) {// 1. 解析客户业务数据(requestDTO.getBusinessData()为JSON字符串)String customerData = requestDTO.getBusinessData();// 示例:假设业务数据是客户新增参数(实际项目用JSON工具解析为实体类)// CustomerAddDTO addDTO = JSON.parseObject(customerData, CustomerAddDTO.class);// 2. 处理客户业务逻辑(如调用DAO新增客户)System.out.println("客户Service处理业务,数据:" + customerData);// 3. 返回结果return BusinessResponseDTO.success("客户业务处理成功", "{\"customerId\":1001,\"status\":\"ACTIVE\"}");}@Overridepublic String[] getSupportBusinessCodes() {// 与@BusinessServiceMapping的value保持一致(便于校验)return new String[]{"DC"};}
}// 示例2:订单业务Service(标识ORD)
@BusinessServiceMapping(value = "ORD", // 业务标识:ORD=订单desc = "订单相关业务处理(创建订单/取消订单)"
)
public class OrderBusinessService implements BusinessProcessService {@Overridepublic BusinessResponseDTO process(BusinessRequestDTO requestDTO) {// 订单业务逻辑处理(类似客户Service)String orderData = requestDTO.getBusinessData();System.out.println("订单Service处理业务,数据:" + orderData);return BusinessResponseDTO.success("订单业务处理成功", "{\"orderId\":2001,\"orderStatus\":\"PAID\"}");}@Overridepublic String[] getSupportBusinessCodes() {return new String[]{"ORD"};}
}

5. 路由服务:BusinessServiceRouter(核心:匹配请求与 Service)

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;/*** 业务Service路由:根据请求的businessCode匹配对应的Service*/
@Component
public class BusinessServiceRouter implements ApplicationContextAware {/*** 业务标识→Service的映射缓存(key:businessCode,value:对应的BusinessProcessService)*/private final Map<String, BusinessProcessService> businessServiceMap = new HashMap<>();/*** Spring启动时,扫描所有带@BusinessServiceMapping的Service,初始化映射*/@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {// 1. 扫描Spring容器中所有实现BusinessProcessService接口的BeanMap<String, BusinessProcessService> serviceBeans = applicationContext.getBeansOfType(BusinessProcessService.class);// 2. 遍历Service,解析@BusinessServiceMapping注解,建立映射for (BusinessProcessService service : serviceBeans.values()) {BusinessServiceMapping mapping = service.getClass().getAnnotation(BusinessServiceMapping.class);if (mapping == null) {continue; // 跳过未标记注解的Service
            }// 3. 为每个业务标识绑定Service(支持一个Service对应多个标识)for (String businessCode : mapping.value()) {if (businessServiceMap.containsKey(businessCode)) {throw new RuntimeException("业务标识[" + businessCode + "]重复绑定Service,请检查@BusinessServiceMapping注解");}businessServiceMap.put(businessCode, service);System.out.println("业务标识[" + businessCode + "]绑定Service:" + service.getClass().getSimpleName());}}// 4. 打印映射结果(便于调试)System.out.println("业务Service映射初始化完成,共" + businessServiceMap.size() + "个标识:" + businessServiceMap.keySet());}/*** 核心方法:根据业务标识获取对应的Service* @param businessCode 业务标识(如DC、ORD)* @return 匹配的BusinessProcessService* @throws RuntimeException 无匹配Service时抛出异常*/public BusinessProcessService getServiceByBusinessCode(String businessCode) {BusinessProcessService service = businessServiceMap.get(businessCode);if (service == null) {throw new RuntimeException("未找到业务标识[" + businessCode + "]对应的Service,请检查配置");}return service;}/*** 统一业务处理入口:路由到对应Service并调用process方法*/public BusinessResponseDTO routeAndProcess(BusinessRequestDTO requestDTO) {if (requestDTO == null || requestDTO.getBusinessCode() == null) {return BusinessResponseDTO.fail("请求参数错误:businessCode不能为空");}try {// 1. 根据businessCode获取ServiceBusinessProcessService service = getServiceByBusinessCode(requestDTO.getBusinessCode());// 2. 调用Service的process方法处理业务return service.process(requestDTO);} catch (RuntimeException e) {// 3. 捕获异常,返回统一错误格式return BusinessResponseDTO.fail("业务处理失败:" + e.getMessage());}}
}

6. 控制层:BusinessController(接收请求,调用路由服务)

import com.yourproject.dto.BusinessRequestDTO;
import com.yourproject.dto.BusinessResponseDTO;
import com.yourproject.service.BusinessServiceRouter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** 统一业务入口Controller:所有业务请求通过此接口进入,由路由服务分发*/
@RestController
@RequestMapping("/api/business")
public class BusinessController {@Autowiredprivate BusinessServiceRouter businessServiceRouter;/*** 统一业务处理接口* @param requestDTO 业务请求(包含businessCode和业务数据)* @return 业务处理结果*/@PostMapping("/process")public BusinessResponseDTO processBusiness(@RequestBody BusinessRequestDTO requestDTO) {// 直接委托路由服务处理,无需硬编码分支return businessServiceRouter.routeAndProcess(requestDTO);}
}

三、核心流程说明

  1. 启动初始化:
    Spring 启动时,BusinessServiceRouter 通过 ApplicationContextAware 扫描所有实现 BusinessProcessService 且带 @BusinessServiceMapping 的 Service,建立 “业务标识→Service” 的映射(如 DC→CustomerBusinessServiceORD→OrderBusinessService)。
  2. 请求处理:
    • 前端发送请求(如客户业务),businessCode=DCbusinessData={"customerName":"张三","phone":"13800138000"}
    • BusinessController 接收请求,调用 BusinessServiceRouter.routeAndProcess
    • 路由服务根据 businessCode=DC 找到 CustomerBusinessService,调用其 process 方法;
    • 处理完成后,返回统一格式的 BusinessResponseDTO

四、扩展与优势

  1. 新增业务:
    若需新增 “产品业务”(标识 PROD),只需:
    • 新建 ProductBusinessService 实现 BusinessProcessService
    • 用 @BusinessServiceMapping(value = "PROD", desc = "产品业务") 标记;
    • 无需修改 Controller 或路由服务,实现 “开闭原则”。
  2. 避免硬编码:
    传统写法需用 if (businessCode.equals("DC")) { 客户Service } else if (...),新增业务需修改代码;此方案通过注解 + 路由,彻底消除硬编码分支。
  3. 便于维护:
    每个业务 Service 职责单一,通过注解清晰标识业务范围,后续维护只需定位到对应 Service 即可。

五、依赖与配置

需确保 Spring 能扫描到注解标记的类,在 Spring Boot 启动类添加扫描路径(默认扫描启动类所在包及子包,若 Service 在其他包需手动指定):
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;@SpringBootApplication
// 若Service在com.yourproject.service包下,默认会扫描,无需额外配置;若路径不同需添加:
// @ComponentScan(basePackages = {"com.yourproject.controller", "com.yourproject.service"})
public class BusinessApplication {public static void main(String[] args) {SpringApplication.run(BusinessApplication.class, args);}
}

 

 

http://www.hskmm.com/?act=detail&tid=9493

相关文章:

  • iOS26正式版全新风格!一文汇总实用新功能!
  • 远程控制应用的中的全球节点功能如何开启?插件类型、并发数量怎么选?
  • 借助Aspose.HTML控件,使用 Python 将 HTML 转换为 DOCX
  • openEuler 24.03 (LTS-SP2)安装mysql 8.0.41
  • 7.数据库归档异常检查与处理
  • Gitlab 关键字
  • 8.listener日志占用过大处理方法
  • 马建仓AI助手完成全链路升级:三十余项新能力重塑研发工作流
  • 线性回归与 Softmax 回归:深度学习基础模型解析 - 实践
  • 浏览器下载,一定要开启这个隐藏功能!
  • 开源项目进度管理系统 PJMan:让技术项目进度可视化、数据化的利器
  • 【光照】[漫反射]UnityURP兰伯特能量守恒吗?
  • Microsoft AI Genius 限时挑战赛:实战开启,等你应战!
  • DevSecOps革命:测试工具如何重塑企业数字化转型的质量防线
  • 3.sysaux tablesace 清理
  • 2.LOCK session
  • 2025 ~ 2026 游击 - gfoi
  • 【初赛】第二类斯特林数意义 - Slayer
  • 在AI技术快速实现功能的时代,挖掘新需求成为核心竞争力——某知名Android面试题库需求洞察
  • php本地搭建知识库实现rag遇到的一些问题解决方式
  • docker操作包括使用docker制作为接口
  • BuildingSystemPlugin使用指南
  • openEuler 24.03 (LTS-SP2)安装mysql5.7.42
  • Trae AI IDE与Gitee MCP深度整合:开启智能协作开发新时代
  • LangChain 入门:从 0 到 1 搞懂 LLM 应用开发框架​
  • [JOI Open 2023] 古代机器 2 / Ancient Machine 2 题解
  • Visual Studio 2022配置fftw第三方库
  • [React] nextjs useSWR导致的死循环,一直重复渲染rerender
  • 使用 Rust 实现的基础的List 和 Watch 机制
  • 解码C语言指针