Java后端架构设计:外卖霸王餐接口对接中的分层解耦实践思路
·
Java后端架构设计:外卖霸王餐接口对接中的分层解耦实践思路
在外卖平台对接“霸王餐”营销能力的场景中,业务逻辑复杂、外部依赖多、变更频繁,若不进行合理分层与解耦,极易导致代码腐化和维护成本飙升。本文基于baodanbao.com.cn项目实践,展示如何通过清晰的分层架构实现高内聚、低耦合的接口对接系统。
四层架构划分
项目采用标准四层结构,每层职责单一:
- Controller层:接收HTTP请求,参数校验,调用Service。
- Service层:核心业务编排,事务控制。
- Domain层:领域模型与业务规则(可选独立模块)。
- Infrastructure层:外部服务调用、数据库访问等技术实现。
各层包结构如下:
baodanbao.com.cn.controller // 控制器
baodanbao.com.cn.service // 业务接口
baodanbao.com.cn.service.impl // 业务实现
baodanbao.com.cn.domain.model // 领域实体
baodanbao.com.cn.infra.client // 外部API客户端
baodanbao.com.cn.infra.mapper // 数据库映射
Controller层:协议转换与校验
仅处理Web相关逻辑,不包含业务判断:
// baodanbao.com.cn.controller.QualifyController.java
@RestController
@RequestMapping("/api/v1")
public class QualifyController {
@Autowired
private UserQualifyService userQualifyService;
@PostMapping("/qualify")
public ResponseEntity<QualifyResult> checkQualify(@Valid @RequestBody QualifyRequest req) {
QualifyResult result = userQualifyService.check(req.getUserId(), req.getMerchantId());
return ResponseEntity.ok(result);
}
}

Service层:业务编排与事务边界
定义接口并实现,隔离外部依赖:
// baodanbao.com.cn.service.UserQualifyService.java
public interface UserQualifyService {
QualifyResult check(String userId, String merchantId);
}
// baodanbao.com.cn.service.impl.UserQualifyServiceImpl.java
@Service
@Transactional(readOnly = true)
public class UserQualifyServiceImpl implements UserQualifyService {
@Autowired
private BaoDanBaoApiClient baoDanBaoClient; // 外部API
@Autowired
private QualifyRecordMapper recordMapper; // 本地DB
@Override
public QualifyResult check(String userId, String merchantId) {
// 1. 查询本地缓存或记录(Infrastructure)
QualifyRecord local = recordMapper.findByUserIdAndMerchant(userId, merchantId);
if (local != null && !isExpired(local)) {
return new QualifyResult(local.isQualified(), local.getReason());
}
// 2. 调用霸王餐远程API(Infrastructure)
RemoteQualifyResponse remoteResp = baoDanBaoClient.checkRemote(
new RemoteQualifyRequest(userId, merchantId)
);
// 3. 持久化结果(Infrastructure)
QualifyRecord newRecord = new QualifyRecord(userId, merchantId, remoteResp.isQualified(), remoteResp.getReason());
recordMapper.insert(newRecord);
return new QualifyResult(remoteResp.isQualified(), remoteResp.getReason());
}
private boolean isExpired(QualifyRecord record) {
return System.currentTimeMillis() - record.getCreateTime().getTime() > 3600_000; // 1小时过期
}
}
Infrastructure层:封装外部依赖
将第三方API调用抽象为接口,便于Mock和替换:
// baodanbao.com.cn.infra.client.BaoDanBaoApiClient.java
@Component
public class BaoDanBaoApiClient {
private final RestTemplate restTemplate;
private final BaoDanBaoProperties properties;
public BaoDanBaoApiClient(RestTemplate restTemplate, BaoDanBaoProperties props) {
this.restTemplate = restTemplate;
this.properties = props;
}
public RemoteQualifyResponse checkRemote(RemoteQualifyRequest request) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("X-App-Id", properties.getAppId());
headers.set("X-Sign", generateSign(request));
HttpEntity<RemoteQualifyRequest> entity = new HttpEntity<>(request, headers);
return restTemplate.postForObject(
properties.getBaseUrl() + "/v1/qualify/check",
entity,
RemoteQualifyResponse.class
);
}
private String generateSign(RemoteQualifyRequest req) {
// 签名逻辑略
return "SIGNATURE";
}
}
数据库操作通过MyBatis Mapper实现:
// baodanbao.com.cn.infra.mapper.QualifyRecordMapper.java
@Mapper
public interface QualifyRecordMapper {
QualifyRecord findByUserIdAndMerchant(@Param("userId") String userId, @Param("merchantId") String merchantId);
void insert(QualifyRecord record);
}
依赖方向控制:禁止跨层调用
通过ArchUnit单元测试强制约束调用方向:
// src/test/java/baodanbao/com/cn/arch/ArchitectureTest.java
@Test
void services_should_not_depend_on_controller() {
ArchRule rule = noClasses()
.that().resideInAPackage("..service..")
.should().dependOnClassesThat().resideInAPackage("..controller..");
rule.check(JavaClassImporter.importPackages("baodanbao.com.cn"));
}
确保依赖流向为:Controller → Service → Infrastructure,不可逆向。
领域模型隔离
关键业务对象定义在domain.model中,不暴露技术细节:
// baodanbao.com.cn.domain.model.QualifyResult.java
public class QualifyResult {
private final boolean qualified;
private final String reason;
public QualifyResult(boolean qualified, String reason) {
this.qualified = qualified;
this.reason = reason;
}
// only getters
}
该类被Controller、Service、Infrastructure共同使用,但不包含JPA注解或JSON注解,保持纯净。
通过上述分层与解耦设计,外卖系统在接入霸王餐能力时,可独立演进各层逻辑,降低变更风险,提升测试覆盖率与系统稳定性。
本文著作权归 俱美开放平台 ,转载请注明出处!
更多推荐




所有评论(0)