四层架构(DDD架构)
2026年1月28日大约 6 分钟
四层架构(DDD架构)
DDD(Domain-Driven Design,领域驱动设计)四层架构是一种分层架构模式,将应用分为用户接口层、应用层、领域层和基础设施层,实现关注点分离和业务逻辑的内聚。
架构层次
┌─────────────────────────────────────┐
│ 用户接口层 (Interface Layer) │
│ Controller / Facade / DTO / VO │
├─────────────────────────────────────┤
│ 应用层 (Application Layer) │
│ Application Service / Use Case │
├─────────────────────────────────────┤
│ 领域层 (Domain Layer) │
│ Entity / Value Object / Domain │
│ Service / Repository Interface │
├─────────────────────────────────────┤
│ 基础设施层 (Infrastructure) │
│ Repository Impl / DB / MQ / Cache │
└─────────────────────────────────────┘1. 用户接口层(Interface Layer)
职责
- 接收用户请求:处理 HTTP 请求、RPC 调用等
- 参数校验:验证请求参数的合法性
- 数据转换:DTO 与领域对象的转换
- 返回响应:将结果转换为 VO 返回给用户
特点
- 薄层设计:不包含业务逻辑,只负责协调
- 协议无关:可以支持 HTTP、RPC、消息队列等多种协议
- 数据验证:使用 Bean Validation 进行参数校验
代码示例
@RestController
@RequestMapping("/api/users")
@Slf4j
public class UserController {
@Autowired
private UserApplicationService userApplicationService;
/**
* 创建用户
*/
@PostMapping
public Result<UserVO> createUser(@Valid @RequestBody UserCreateDTO dto) {
// 1. DTO 转领域对象
User user = User.builder()
.userName(dto.getUserName())
.email(dto.getEmail())
.password(dto.getPassword())
.build();
// 2. 调用应用服务
User createdUser = userApplicationService.createUser(user);
// 3. 领域对象转 VO
UserVO vo = UserVO.builder()
.id(createdUser.getId())
.userName(createdUser.getUserName())
.email(createdUser.getEmail())
.build();
return Result.success(vo);
}
/**
* 查询用户
*/
@GetMapping("/{id}")
public Result<UserVO> getUser(@PathVariable Long id) {
User user = userApplicationService.getUser(id);
UserVO vo = convertToVO(user);
return Result.success(vo);
}
}2. 应用层(Application Layer)
职责
- 编排业务流程:协调多个领域服务完成业务用例
- 事务管理:管理事务边界
- 权限控制:进行权限校验
- 领域对象转换:DTO 与领域对象的转换
特点
- 用例驱动:每个方法对应一个业务用例
- 无状态:应用服务应该是无状态的
- 薄层设计:不包含业务逻辑,只负责编排
代码示例
@Service
@Transactional
@Slf4j
public class UserApplicationService {
@Autowired
private UserRepository userRepository;
@Autowired
private UserDomainService userDomainService;
@Autowired
private EmailService emailService;
/**
* 创建用户用例
*/
public User createUser(User user) {
// 1. 业务规则校验(委托给领域服务)
userDomainService.validateUserCreation(user);
// 2. 保存用户(委托给领域对象)
User savedUser = userRepository.save(user);
// 3. 发送欢迎邮件(应用层协调)
emailService.sendWelcomeEmail(savedUser.getEmail());
// 4. 发布领域事件(可选)
domainEventPublisher.publish(new UserCreatedEvent(savedUser.getId()));
return savedUser;
}
/**
* 查询用户用例
*/
@Transactional(readOnly = true)
public User getUser(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("用户不存在"));
}
/**
* 更新用户用例
*/
public User updateUser(Long id, UserUpdateDTO dto) {
User user = getUser(id);
// 委托给领域对象处理更新逻辑
user.updateEmail(dto.getEmail());
user.updateAge(dto.getAge());
return userRepository.save(user);
}
}3. 领域层(Domain Layer)
职责
- 业务逻辑:包含核心业务逻辑和业务规则
- 领域模型:定义实体(Entity)、值对象(Value Object)
- 领域服务:处理跨实体的业务逻辑
- 仓储接口:定义数据访问接口(不包含实现)
特点
- 业务核心:包含最重要的业务逻辑
- 技术无关:不依赖具体的技术实现
- 高内聚:相关业务逻辑聚集在一起
代码示例
实体(Entity)
/**
* 用户实体(有唯一标识)
*/
@Entity
public class User {
private Long id; // 唯一标识
private String userName;
private String email;
private String password;
private UserStatus status;
/**
* 业务方法:激活用户
*/
public void activate() {
if (this.status == UserStatus.ACTIVE) {
throw new BusinessException("用户已经是激活状态");
}
this.status = UserStatus.ACTIVE;
}
/**
* 业务方法:更新邮箱
*/
public void updateEmail(String newEmail) {
if (newEmail == null || !isValidEmail(newEmail)) {
throw new BusinessException("邮箱格式不正确");
}
this.email = newEmail;
}
/**
* 业务方法:修改密码
*/
public void changePassword(String oldPassword, String newPassword) {
if (!this.password.equals(encrypt(oldPassword))) {
throw new BusinessException("原密码不正确");
}
if (newPassword.length() < 6) {
throw new BusinessException("新密码长度不能少于6位");
}
this.password = encrypt(newPassword);
}
private boolean isValidEmail(String email) {
// 邮箱验证逻辑
return email.matches("^[A-Za-z0-9+_.-]+@(.+)$");
}
private String encrypt(String password) {
// 密码加密逻辑
return DigestUtils.md5DigestAsHex(password.getBytes());
}
}值对象(Value Object)
/**
* 邮箱值对象(无唯一标识,通过值比较相等性)
*/
public class Email {
private final String value;
public Email(String value) {
if (value == null || !isValid(value)) {
throw new IllegalArgumentException("邮箱格式不正确");
}
this.value = value;
}
public String getValue() {
return value;
}
private boolean isValid(String email) {
return email.matches("^[A-Za-z0-9+_.-]+@(.+)$");
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Email email = (Email) o;
return Objects.equals(value, email.value);
}
@Override
public int hashCode() {
return Objects.hash(value);
}
}领域服务(Domain Service)
/**
* 用户领域服务(处理跨实体的业务逻辑)
*/
@Service
public class UserDomainService {
@Autowired
private UserRepository userRepository;
/**
* 验证用户创建的业务规则
*/
public void validateUserCreation(User user) {
// 检查用户名是否已存在
if (userRepository.existsByUserName(user.getUserName())) {
throw new BusinessException("用户名已存在");
}
// 检查邮箱是否已存在
if (userRepository.existsByEmail(user.getEmail())) {
throw new BusinessException("邮箱已被注册");
}
// 其他业务规则校验
if (user.getAge() != null && user.getAge() < 18) {
throw new BusinessException("用户年龄不能小于18岁");
}
}
/**
* 计算用户信用等级(跨实体逻辑)
*/
public CreditLevel calculateCreditLevel(User user, List<Order> orders) {
// 根据用户信息和订单历史计算信用等级
int orderCount = orders.size();
BigDecimal totalAmount = orders.stream()
.map(Order::getAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
if (orderCount > 100 && totalAmount.compareTo(new BigDecimal("100000")) > 0) {
return CreditLevel.PLATINUM;
} else if (orderCount > 50) {
return CreditLevel.GOLD;
} else {
return CreditLevel.SILVER;
}
}
}仓储接口(Repository Interface)
/**
* 用户仓储接口(定义在领域层,实现在基础设施层)
*/
public interface UserRepository {
User save(User user);
Optional<User> findById(Long id);
Optional<User> findByUserName(String userName);
Optional<User> findByEmail(String email);
boolean existsByUserName(String userName);
boolean existsByEmail(String email);
List<User> findAll();
void delete(Long id);
}4. 基础设施层(Infrastructure Layer)
职责
- 技术实现:实现仓储接口、消息队列、缓存等
- 数据持久化:数据库访问、文件存储等
- 外部服务:调用第三方服务、发送邮件等
- 框架集成:Spring、MyBatis、Redis 等框架的配置
特点
- 技术相关:包含具体的技术实现
- 可替换:可以替换不同的实现而不影响领域层
- 工具性质:为上层提供技术支撑
代码示例
仓储实现(Repository Implementation)
/**
* 用户仓储实现(基础设施层)
*/
@Repository
public class UserRepositoryImpl implements UserRepository {
@Autowired
private UserMapper userMapper; // MyBatis Mapper
@Override
public User save(User user) {
if (user.getId() == null) {
userMapper.insert(user);
} else {
userMapper.updateById(user);
}
return user;
}
@Override
public Optional<User> findById(Long id) {
User user = userMapper.selectById(id);
return Optional.ofNullable(user);
}
@Override
public Optional<User> findByUserName(String userName) {
User user = userMapper.selectByUserName(userName);
return Optional.ofNullable(user);
}
@Override
public boolean existsByUserName(String userName) {
return userMapper.countByUserName(userName) > 0;
}
// 其他方法实现...
}外部服务实现
/**
* 邮件服务实现(基础设施层)
*/
@Service
public class EmailServiceImpl implements EmailService {
@Autowired
private JavaMailSender mailSender;
@Override
public void sendWelcomeEmail(String email) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(email);
message.setSubject("欢迎注册");
message.setText("欢迎您注册我们的服务!");
mailSender.send(message);
}
}依赖方向
用户接口层 → 应用层 → 领域层 ← 基础设施层- 领域层:不依赖任何其他层,是核心
- 应用层:依赖领域层
- 用户接口层:依赖应用层和领域层
- 基础设施层:依赖领域层(实现领域层定义的接口)
最佳实践
- 领域层为核心:业务逻辑集中在领域层
- 应用层编排:应用层只负责编排,不包含业务逻辑
- 接口在领域层:仓储接口定义在领域层,实现在基础设施层
- 依赖倒置:通过接口实现依赖倒置,领域层不依赖基础设施层
- 领域事件:使用领域事件实现解耦
- 值对象优先:优先使用值对象封装业务概念
- 聚合根:合理设计聚合根,控制事务边界
- 避免贫血模型:实体应该包含业务方法,而不是只有 getter/setter
