策略模式在Spring Boot中的实战应用:动态数据源切换方案

发布时间:2026/6/30 2:42:23
策略模式在Spring Boot中的实战应用:动态数据源切换方案 本文通过“业务算法动态切换不同数据源”的典型场景系统介绍了策略模式的核心概念与 Spring Boot 落地实践。文章从模式定义、角色构成出发给出了完整的多文件项目结构和可直接运行的代码示例重点演示了如何利用 Spring 的依赖注入特性实现策略的自动注册与运行时切换彻底消除 if-else 分支。同时展示了新增数据源时如何做到零侵入扩展完美践行开闭原则提供了一套清晰、优雅、可复用的设计模板。一、策略模式Strategy Pattern介绍定义策略模式定义了一系列算法或功能将每个算法封装起来并使它们可以相互替换。策略模式让算法的变化独立于使用它的客户端。核心角色对应你的案例抽象策略Strategy定义统一的业务接口如数据拉取方法fetchData。具体策略ConcreteStrategy实现接口的具体类如DBSource、ApiSource。上下文Context持有策略引用并执行算法的类如业务算法服务AlgorithmContext。为什么用在这里优点消除臃肿的 if-else切换数据源通过类型字符串直接从Map获取业务逻辑内无任何条件分支。开闭原则新增第 3 种数据源如 Redis只需新增类加注解业务算法和调用方零修改。便于单元测试可以轻松注入 Mock 策略类进行算法逻辑测试无需依赖真实数据库或网络。二、项目文件目录结构Spring Boot 标准src/main/java/com/example/demo/ ├── DemoApplication.java // Spring Boot 启动类 ├── strategy/ // 策略包 │ ├── Strategy.java // 抽象策略接口 │ ├── DBSource.java // 具体策略A数据库 │ └── ApiSource.java // 具体策略B外部API ├── service/ // 业务服务包 │ └── AlgorithmContext.java // 上下文核心业务算法 └── controller/ // 控制器包 └── TestController.java // REST接口接收前端切换参数三、完整代码实现每个类单独文件1.DemoApplication.java启动类packagecom.example.demo;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplicationpublicclassDemoApplication{publicstaticvoidmain(String[]args){SpringApplication.run(DemoApplication.class,args);}}2.strategy/Strategy.java抽象策略接口packagecom.example.demo.strategy;publicinterfaceStrategy{// 统一的数据拉取契约StringfetchData(Stringkey);}3.strategy/DBSource.java数据库具体策略注意Component(db)指定 Bean 名称Spring 会将其自动注册到策略 Map 中Key 为db。packagecom.example.demo.strategy;importorg.springframework.stereotype.Component;Component(db)publicclassDBSourceimplementsStrategy{OverridepublicStringfetchData(Stringkey){// 实际开发中此处放 JDBC / MyBatis / JPA 查询代码return【DB数据库】内容 for key: key;}}4.strategy/ApiSource.javaAPI 接口具体策略packagecom.example.demo.strategy;importorg.springframework.stereotype.Component;Component(api)publicclassApiSourceimplementsStrategy{OverridepublicStringfetchData(Stringkey){// 实际开发中此处放 RestTemplate / WebClient / HttpClient 调用return【API接口】内容 for key: key;}}5.service/AlgorithmContext.java上下文 / 核心业务算法核心逻辑Spring 会自动将所有Strategy实现类注入到MapString, Strategy中。算法根据传入的type如db直接获取策略彻底消灭 if-else。packagecom.example.demo.service;importcom.example.demo.strategy.Strategy;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importjava.util.Map;ServicepublicclassAlgorithmContext{AutowiredprivateMapString,StrategystrategyMap;// Key是Component指定的名称Value是策略实例publicStringexecuteAlgorithm(Stringtype,Stringkey){// 1. 根据传入类型如 db从Map中获取策略StrategystrategystrategyMap.get(type);if(strategynull){thrownewIllegalArgumentException(未知的数据源类型: type);}// 2. 拉取原始数据面向接口多态调用StringrawDatastrategy.fetchData(key);// 3. 核心业务逻辑假设转大写 计算字符串长度Stringresult【算法结果】rawData.toUpperCase()长度rawData.length();// 4. 返回结果给调用方Controllerreturnresult;}}6.controller/TestController.javaRESTful 控制器前端只需传typedb或typeapi即可动态切换数据源。packagecom.example.demo.controller;importcom.example.demo.service.AlgorithmContext;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RequestParam;importorg.springframework.web.bind.annotation.RestController;RestControllerpublicclassTestController{AutowiredprivateAlgorithmContextalgorithmContext;GetMapping(/compute)publicStringcompute(RequestParamStringtype,// 前端传入 db 或 apiRequestParamStringkey// 查询键值){returnalgorithmContext.executeAlgorithm(type,key);}}四、运行测试启动 Spring Boot 应用后在浏览器或 Postman 中访问切换数据库源GET http://localhost:8080/compute?typedbkeyuser_001输出【算法结果】【DB数据库】内容 FOR KEY: USER_001长度25切换 API 源GET http://localhost:8080/compute?typeapikeyorder_999输出【算法结果】【API接口】内容 FOR KEY: ORDER_999长度26五、如何扩展第 3 种数据源演示开闭原则假设未来要接入Redis数据源无需修改任何已有代码新建strategy/RedisSource.javapackagecom.example.demo.strategy;importorg.springframework.stereotype.Component;Component(redis)// 新类型publicclassRedisSourceimplementsStrategy{OverridepublicStringfetchData(Stringkey){return【Redis缓存】内容 for key: key;}}重启应用前端直接传typeredisAlgorithmContext和Controller一行代码都不用改自动生效。