何为领域事件
领域事件是用来捕获发生在领域之间的一些事件,用来帮助不同领域甚至不同限界上下文来进行解耦。所以领域事件可以被本地的限界上下文所消费也可以被外部的限界上下文所消费。当采用本地的限界上下文所消费时,通常使用的是Spring Data的domain event所实现。被外部上下文所消费的情况下一般是采用消息队列的形式。当然也可以采用拉取的方式,比如rest服务。
Spring Data发布领域事件
用Spring Data来发布领域事件一共有两种方式,分别是AggregateRoot和@DomainEvents注解方法发布事件
方式一 AggregateRoot
实现AbstractAggregateRoot接口,调用registerEvent()方法发布领域事件
定义领域事件
@Data
@AllArgsConstructor
public class OrderFinishedEvent {
private Long customerId;
}
发布领域事件
@Entity
@Table(name = "ef_order")
@Data
@ToString(exclude = "orderRecordEntityList")
@EntityListeners(AuditingEntityListener.class)
@Slf4j
public class OrderEntity extends AbstractAggregateRoot<OrderEntity> implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String orderNo;
/**
* 订单状态
*
* @see OrderStatusEnum
*/
private Integer status;
public OrderEntity confirmReceived(DealerConfirmDTO dto) {
//todo 业务逻辑
//发布领域事件
registerEvent(new OrderFinishedEvent(this.customerId));
return this;
}
}
监听处理事件
@Component
@Slf4j
public class OrderEventReceiver{
@Autowired
private CustomerAppService customerAppService;
@Async
@TransactionalEventListener
@AutoLog("订单完成-更新客户")
public void handleOrderFinished(OrderFinishedEvent event){
if(Objects.isNull(event)){
return;
}
customerAppService.updateCustomerCondition(event.getCustomerId());
}
}
使用@DomainEvents注解方法发布事件
@Entity
@Table(name = "ef_order")
@Data
@ToString(exclude = "orderRecordEntityList")
@EntityListeners(AuditingEntityListener.class)
@ToString(exclude = "domainEvents")
public class OrderEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String orderNo;
/**
* 订单状态
*
* @see OrderStatusEnum
*/
private Integer status;
//@DomainEvents可以返回单个事件实例或事件集合,@DomainEvents用来发布时间,触发机制在保存的时候。批量保存对象时,每个对象都会触发一次事件
@DomainEvents
Collection<Object> domainEvents() {
List<Object> events= new ArrayList<Object>();
events.add(new OrderFinishedEvent(this.id));
return events;
}
//@AfterDomainEventPublication在事件发布之后触发。批量保存时触发多次
@AfterDomainEventPublication
void callbackMethod() {
}
}
从上面的用法不难看出,AbstractAggregateRoot相对于@DomainEvents使用更加灵活,@DomainEvents是指定在持久化对象后发布领域事件。而registerEvent()方法可以在任意时间点调用