java-architecture-guide
Java 业务项目架构指南
分层架构
四层单向调用,禁止反向或跨层依赖:
Controller → Facade → Service → Repository (Mapper)
各层职责
| 层 | 职责 | 注入 | 禁止 |
|---|---|---|---|
| Controller | HTTP 入口、参数校验、响应封装 | Facade | 注入 Service;包含业务逻辑;添加事务 |
| Facade | 跨服务编排、事务边界、DTO 组装 | 多个 Service、Converter | 直接操作 Mapper |
| Service | 单一领域业务逻辑、数据操作 | 本域 Mapper、Converter | 注入其他 Service 或其他域的 Mapper |
| Repository | 数据访问(继承 BaseMapper) | — | 添加自定义方法(查询在 Service 中构建) |
为什么引入 Facade 层
- 单一职责: Service 层专注自己领域,不承担编排逻辑
- 降低耦合: Service 不依赖其他 Service,可独立测试
- 事务清晰: 跨服务事务统一在 Facade 管理
- 便于定位: 业务编排集中在 Facade,排查问题路径清晰
层间调用铁律
规则 1: Controller 只注入 Facade
// CORRECT
@RestController
@RequiredArgsConstructor
public class PolicyController {
private final PolicyFacade facade; // ✅
@PostMapping
public ApiResponse<IdResp> create(@Valid @RequestBody PolicyCreateReq req) {
return ApiResponse.ok(new IdResp(facade.create(req)));
}
}
// WRONG
public class PolicyController {
private final PolicyService service; // ❌ 禁止直接注入 Service
}
规则 2: Service 禁止注入其他 Service
这是最常被违反的规则。跨域数据需求必须上推到 Facade 层。
// WRONG - Service 跨域调用
@Service
public class AlgoServiceServiceImpl {
private final LlmServiceMapper llmServiceMapper; // ❌ 注入其他域 Mapper
private final VideoSourceService videoSourceService; // ❌ 注入其他 Service
}
// CORRECT - Facade 编排
@Component
@RequiredArgsConstructor
public class AlgoServiceFacade {
private final AlgoServiceService algoServiceService; // ✅
private final LlmServiceService llmServiceService; // ✅ Facade 注入多个 Service
public AlgoServiceDetail getDetail(Long id) {
AlgoServiceDetail detail = algoServiceService.getDetail(id);
if (detail.getLlmServiceId() != null) {
LlmService llm = llmServiceService.getById(detail.getLlmServiceId());
detail.setLlmServiceName(llm.getName());
}
return detail;
}
}
规则 3: Mapper 保持空接口
查询逻辑在 Service 中使用 LambdaQueryWrapper 构建,保证类型安全。
禁止 在 Mapper 中新增方法或 Mapper XML 自定义 SQL,复杂条件仍在 Service 使用 Wrapper/apply 构建。
// CORRECT
@Mapper
public interface PolicyMapper extends BaseMapper<AlertPolicy> {
// 空接口,不添加任何方法
}
// Service 中构建查询
LambdaQueryWrapper<AlertPolicy> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(AlertPolicy::getEnabled, true)
.orderByDesc(AlertPolicy::getCreateTime);
List<AlertPolicy> list = baseMapper.selectList(wrapper);
// WRONG
@Mapper
public interface PolicyMapper extends BaseMapper<AlertPolicy> {
@Select("SELECT * FROM alert_policy WHERE enabled = 1") // ❌
List<AlertPolicy> findEnabled();
}
事务管理
事务边界
| 场景 | 事务位置 | 示例 |
|---|---|---|
| 跨服务写操作 | Facade 层 | 创建任务 + 创建子任务 |
| 单服务复杂写操作 | Service 层 | 批量删除 + 依赖检查 |
| 读操作 | 无事务 | 查询列表、查询详情 |
| Controller 层 | 禁止 | — |
事务注解标准写法
@Transactional(rollbackFor = Exception.class)
public Long create(TaskCreateReq req) {
// 业务逻辑
}
事务内禁止
- 远程调用(HTTP / RPC / 消息发送)
- 耗时操作(文件 IO、大量计算)
@Async方法调用
异常处理体系
异常层次
RuntimeException
└── BusinessException (业务异常,含 ErrorCode)
└── AuthConsoleException (外部系统异常)
各层异常职责
| 层 | 职责 |
|---|---|
| Service | 抛出 BusinessException(资源不存在、业务规则违反) |
| Facade | 不捕获 BusinessException,透传给全局处理器;仅捕获需要补偿的外部调用异常 |
| Controller | 不处理异常 |
| GlobalExceptionHandler | 统一捕获,转换为 ApiResponse |
错误码分段管理
按业务模块分配错误码范围(如 2xxx 算法服务、3xxx 预警策略),避免冲突。
日志级别规范
| 场景 | 级别 | 堆栈 |
|---|---|---|
| 业务异常(BusinessException) | WARN | 无 |
| 参数校验失败 | WARN | 无 |
| 系统异常(未预期) | ERROR | 有 |
| 关键业务操作(创建/更新/删除) | INFO | 无 |
命名规范
Java 命名
| 类型 | 规则 | 示例 |
|---|---|---|
| 类名 | PascalCase | AnalysisTaskService |
| 方法 / 变量 | camelCase | getTaskById, videoSourceId |
| 常量 | UPPER_SNAKE_CASE | MAX_RETRY_COUNT |
| 包名 | 全小写 | com.example.service.impl |
分层命名
| 类型 | 命名模式 |
|---|---|
| Controller | {Resource}Controller |
| Facade | {Resource}Facade (直接类,无接口) |
| Service 接口 | {Resource}Service |
| Service 实现 | {Resource}ServiceImpl |
| Mapper | {Resource}Mapper |
| Entity | {Resource} |
| Converter | {Resource}Converter |
数据库命名
| 类型 | 规则 | 示例 |
|---|---|---|
| 表名 | snake_case | alert_policy, video_source_cache |
| 字段名 | snake_case | create_time, llm_service_id |
| 外键字段 | {关联表}_id |
policy_id, task_id |
| 唯一索引 | uk_{fields} |
uk_name_version |
| 普通索引 | idx_{fields} |
idx_create_time |
API 路径
- 格式:
/api/v{version}/{resources}(复数, kebab-case) - 示例:
/api/v1/llm-services,/api/v1/analysis-tasks
代码质量原则
必须遵守
- 公共 API 方法必须有 Javadoc
- 使用
LambdaQueryWrapper保证类型安全,避免字符串列名 - 不使用物理外键约束,通过应用层保证数据一致性
- 所有表使用逻辑删除(
deleted字段) - 写操作考虑乐观锁(
version_num字段) - 删除前检查依赖关系,防止数据不一致
统一响应格式
所有 API 返回 ApiResponse<T>:
ApiResponse.ok() // 无数据成功
ApiResponse.ok(data) // 带数据成功
ApiResponse.error(code, msg) // 错误
参数校验
- Request Body:
@Valid @RequestBody XxxReq req - Path Variable 校验: 类上加
@Validated,参数上加@NotBlank - 校验注解:
@NotBlank,@NotNull,@NotEmpty(Jakarta Validation)
常见反模式
| 反模式 | 为什么不行 | 正确做法 |
|---|---|---|
| Service 注入其他 Service | 循环依赖、职责混乱、难以测试 | 跨域编排放 Facade 层 |
| Controller 直接调用 Service | 跳过 Facade 编排层,业务逻辑散落 | Controller → Facade → Service |
| Mapper 中写自定义 SQL | 丢失类型安全,SQL 散落 | Service 中用 LambdaQueryWrapper |
| 事务内做 HTTP/RPC 调用 | 长事务、锁争用、调用失败导致回滚 | 事务外调用,或拆分事务 |
| 捕获 BusinessException 后吞掉 | 错误被隐藏,调用方无法感知 | 让全局处理器统一处理 |
| Entity 直接作为 API 响应 | 暴露内部结构,难以演化 | 使用 DTO 做 API 契约 |
| 不指定 rollbackFor | 默认只回滚 RuntimeException | @Transactional(rollbackFor = Exception.class) |
More from jianyun8023/my-skills
java-crud-module
Scaffold a complete CRUD business module for Spring Boot + MyBatis-Plus layered architecture. Creates all 9 required files (Migration, Entity, Mapper, DTOs, Converter, Service, Facade, Controller) following established conventions. Use when creating a new business module, CRUD feature, or module scaffolding.
9java-dto-converter
Create DTOs and MapStruct converters for Spring Boot layered architecture projects. Covers naming conventions, validation annotations, OpenAPI schemas, and conversion patterns. Use when creating DTOs, request/response objects, converters, object mapping, or when working with MapStruct.
4fnos-fpk-dev
飞牛 fnOS FPK 应用包开发指南。涵盖目录结构、manifest 配置、生命周期脚本、用户向导、权限管理、resource 资源声明和桌面图标配置。Use when developing fnOS FPK packages, creating fnOS apps, writing cmd scripts, configuring wizard/manifest/privilege/resource, desktop icons, ui/config, or when the user mentions 飞牛、fnOS、fpk。
2calibre-library
>-
1java-api-endpoint
Add RESTful API endpoints to Spring Boot projects following layered architecture conventions. Covers Controller, Facade patterns, pagination, batch operations, and OpenAPI annotations. Use when adding API endpoints, creating REST interfaces, or implementing query/mutation operations.
1grafana-alloy-hcl
Grafana Alloy HCL 配置文件编写指南。涵盖基本语法、核心组件(Loki/Prometheus)、日志采集、数据处理流水线及 FnOS 特定配置模式。Use when editing .alloy files, configuring Grafana Alloy, setting up log pipelines, or debugging Alloy configurations.
1