DDD 分包分层规范及通用组件说明
- adapter: web层(应用层)
- domain: 领域层
- infrastructure:数据层
- app:应用层
- rpc: 远程rpc调用
- component: 基础组件层
rpc层可以单独拆分一个模块出来,地位和infrastructure层一致,都是属于数据层,也可以直接放在infrastructure层 整体架构设计参考CLOA阿里简洁架构设计 没有一层不变的架构设计,只有最合适的
mybatis plus代码生成器推荐使用 mybatis-plus-generator
就是不要将mybatis plus的Warpper暴露到DAO以外的层级,特别是Service层
不然造成的后果就是Warpper在Service满天飞。然后有如下弊端
Service层充满了数据查询的各种Warpper,逻辑不够解耦,导致应该在数据层的逻辑全部暴露在Service层Service层的数据查询没有封装无法复用
所以我们一般使用mybatis plus的标准用法结构是
- infra
- dao
- mapper
- OrderMapper.java
- impl
- OrderDAOImpl.java OrderDAO.java
- mapper
- entity
- OrderDO.java
- dao
具体的代码如下:
- OrderDO
@Data
public class OrderDO {
}- OrderMapper
@Mapper
public interface OrderMapper extends BaseMapper<OrderDO> {
}- OrderDAO
public interface OrderDAO extends IService<OrderDO> {
}- OrderDAOImpl
@Repository
@RequiredArgsConstructor
public class OrderDAOImpl extends ServiceImpl<OrderMapper, OrderDO> implements OrderDAO {
private final InfluhubOrderMapper influhub_orderMapper;
}缓存框架推荐使用 fluxcache
idea代码格式统一使用 spring-boot-nebula style
依赖注意统一采用构造器注入,不要使用@Autowired注解
结合lombok的@RequiredArgsConstructor注解
@Slf4j
@RestController("/order/v1")
@RequiredArgsConstructor
public class OrderController {
private final OrderApplicationService orderApplicationService;
}参数校验禁止在controller层进行校验,应该在service层进行校验
详细说明参考博客参数校验
集成测试推荐使用MockMvc进行测试
不同领域之间的通信我们都推荐使用事件通信。
任何现实业务逻辑的变化都会有相应的事件触发,从而触发下游业务逻辑的变更
比如下单操作,就出发了一个下单时间,这时候对于下单时间我们需要有其他业务逻辑的处理就形成了解耦。 我们不需要再下单之后修改原有的下单逻辑,只需要监听下单逻辑,然后处理相应的时间。比如下单后需要扣减库存、添加积分等。 都是一个个独立的事件监听,相互不会影响
事件驱动不要使用spring event,会丢失事件
推荐自研或者参考event-bus-rocketmq-all
public class OrderMessage extends EventBusAbstractMessage {
public static final String TAG = "order-tag";
@Override
public String getTag() {
return TAG;
}
}@Slf4j
@Service
@RequiredArgsConstructor
@Validated
public class OrderApplicationService {
private final DomainEventBus domainEventBus;
public boolean createOrder() {
// 下单成功 发送领域事件
OrderMessage orderMessage = new OrderMessage();
domainEventBus.sendMessage(orderMessage);
return true;
}
}@EventBusConsumer(topic = MQConstants.DOMAIN_EVENT_TOPIC, groupId = MQConstants.GID_DOMAIN_EVENT)
@Slf4j
public class OrderEventHandle {
@EventBusListener(tag = OrderMessage.TAG)
public void test(TestMessage testMessage) {
String jsonString = JsonUtil.toJSONString(testMessage);
System.out.println("testMessage = " + jsonString);
}
}如果使用领域事件,必然存在分布式事务问题。 存在两种选择
- 先发领域事件,后提交事务
- 先提交事务,后发领域事件
推荐先提交事务后发领域事件 有两种方式
- 发送延时消息
- 利用
TransactionSynchronizationManager
@Transactional
public void createOrder() {
// 业务逻辑
// 发送领域事件
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
// 发送领域事件
}
});
}一般情况下我们认为领域事件发送失败概率比较小,所以我们可以先提交事务(事务提交失败概率会大一点,比如业务逻辑导致的数据重复插入、数据异常插入失败等),再发送领域事件
领域事件发送的数据尽量不应该依赖于数据库。
分布式事务我们可以不处理,如果处理推荐使用最终一致性
上帝聚合根是指一个聚合根包含了所有的业务逻辑,这样的聚合根会变得非常臃肿,不利于维护和扩展。
- 非特殊配置只有定义
public方法上面的@Transactional才生效 - 必须通过代理过的类从外部调用目标方法才生效
- 默认只有出现
RuntimeException或者Error才会回滚。所以强制指定异常的回滚范围比如@Transactional(rollbackFor = Exception.class) - 合理使用事务的传播行为
分支创建规范参考 git-flow
- 数组单条件查询
存在某个标签
<if test=" dto.tag != null">
and #{dto.tag} = ANY(tags)
</if>- 数组多条件查询
存在多个标签
<if test="dto.tags != null and dto.tags.size() > 0">
AND tags @> ARRAY[
<foreach collection="dto.tags" item="tag" separator=",">
#{tag}::text
</foreach>
]::text[]
</if>- IntelliJ IDEA java编码最好用idea
- GoLand golang编码软件
- DataGrip 数据库管理软件
- Postman 接口调试软件
- Apifox 接口调试软件
- Visual Studio Code 啥都能写
- Xnip 截图软件
- Tabby 终端软件
- RedisInsight Redis可视化软件
- prettyZoo Zookeeper可视化软件
- Sublime Text 文本编辑器
- mat java dump分析工具
- Docker 容器软件
- Charles 抓包软件
- Beyond Compare 文件对比软件
- uTools 各种小工具
- Google Chrome 浏览器
