Spring Boot生产应用:将Repository的CRUD方法转为REST API调用
改造Spring Boot应用CRUD操作为REST API调用方案
方案A:改造业务层CRUD调用为API通信
该方案无需改动Repository层,仅在Service/Manager层将原Repository调用替换为REST API请求,适合希望保留现有Repository抽象的场景。
具体实现
- 封装通用API调用工具
基于SpringWebClient封装通用请求工具,统一处理请求头、序列化、异常:
@Component public class ApiClient { private final WebClient webClient; public ApiClient(WebClient.Builder webClientBuilder) { this.webClient = webClientBuilder.baseUrl("https://api-server-base-url").build(); } // 对应save操作的POST请求 public <T> T post(String path, T requestBody, Class<T> responseType) { return webClient.post() .uri(path) .contentType(MediaType.APPLICATION_JSON) .bodyValue(requestBody) .retrieve() .bodyToMono(responseType) .block(); } // 对应findAll操作的GET列表请求 public <T> List<T> getList(String path, Class<T> elementType) { return webClient.get() .uri(path) .retrieve() .bodyToFlux(elementType) .collectList() .block(); } // 对应delete操作的DELETE请求 public void delete(String path) { webClient.delete() .uri(path) .retrieve() .toBodilessEntity() .block(); } }
- 替换业务层的Repository调用
在Service/Manager类中注入ApiClient,替换原Repository方法调用:
@Service public class SomeService { // 移除原Repository依赖 // @Autowired // private SomeRepository someRepository; @Autowired private ApiClient apiClient; public SomeObject saveSomeObject(SomeObject obj) { // 原代码:return someRepository.save(obj); return apiClient.post("/objects", obj, SomeObject.class); } public List<SomeObject> getAllObjects(String criterion) { // 原代码:return someOtherRepository.findAll(criterion); return apiClient.getList("/objects?criterion=" + criterion, SomeObject.class); } }
- 多数据源适配
针对两个不同数据源的API服务,创建多个ApiClient实例区分:
@Configuration public class ApiClientConfig { @Bean("ds1ApiClient") public ApiClient ds1ApiClient(WebClient.Builder webClientBuilder) { return new ApiClient(webClientBuilder.baseUrl("https://api-ds1-url")); } @Bean("ds2ApiClient") public ApiClient ds2ApiClient(WebClient.Builder webClientBuilder) { return new ApiClient(webClientBuilder.baseUrl("https://api-ds2-url")); } }
业务层注入时通过@Qualifier("ds1ApiClient")指定对应实例即可。
方案B:修改Repository层为REST API实现
该方案直接替换Repository的底层实现,让Repository自身调用REST API,业务层代码无需修改,适合希望保持业务逻辑代码结构不变的场景。
具体实现
- 自定义Repository实现类
不再依赖Spring Data JPA自动生成的实现,手动编写Repository接口的实现类:
@Repository public class SomeRepositoryImpl implements SomeRepository { private final WebClient webClient; public SomeRepositoryImpl(WebClient.Builder webClientBuilder) { this.webClient = webClientBuilder.baseUrl("https://api-server-url").build(); } @Override public <S extends SomeObject> S save(S entity) { return webClient.post() .uri("/objects") .contentType(MediaType.APPLICATION_JSON) .bodyValue(entity) .retrieve() .bodyToMono((Class<S>) entity.getClass()) .block(); } @Override public List<SomeObject> findAll(String criterion) { return webClient.get() .uri("/objects?criterion=" + criterion) .retrieve() .bodyToFlux(SomeObject.class) .collectList() .block(); } // 实现其他CRUD方法(如delete、findById等) }
- 禁用Spring Data自动Repository生成
在启动类排除JPA自动配置,避免冲突:
@SpringBootApplication(exclude = JpaRepositoriesAutoConfiguration.class) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
- 多数据源Repository适配
为不同数据源的Repository分别编写实现类,配置对应API地址,业务层通过@Qualifier区分注入即可。
通用注意事项
- 异常处理:新增全局异常处理器,捕获API请求的HTTP异常(4xx/5xx)并转换为业务异常,保持原有异常体系一致。
- 性能优化:高并发场景建议使用
WebClient异步调用(移除block()),结合Mono/Flux实现非阻塞处理。 - 事务替代:原数据库事务需替换为分布式事务(如Seata)或API层面的补偿机制,REST API不具备ACID特性。
- 测试适配:编写集成测试时,通过Mock工具模拟API服务返回,避免依赖外部服务。
内容的提问来源于stack exchange,提问作者10101010
相关产品推荐
相关产品推荐

