Spring Boot 2.x实战68 - Spring Data 12 - Spring Data JPA领域事件(Domain Events)

2.8 领域事件

由于在DDD中采用了“设计小聚合”的原则,因此避免了领域模型的相互关联,从而避免了在应用演进中形成“大泥球”(Big Ball of Mud),也因为上述的原因,本书将不讲解@OneToMany、@ManyToMany等关联注解。聚合之间在没有了关联关系后,聚合之间的数据通讯通过领域事件来完成,领域事件是由聚合根发出的。

Spring Data对领域事件做了专门的支持,使用@DomainEvents注解注册领域事件或者继承AbstractAggregateRoot使用它的registerEvent方法注册事件。

@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class Person {
    @DomainEvents // 使用集合类注册事件列表
    Collection<Object> domainEvents(){
        List<Object> events= new ArrayList<Object>();
        events.add(new PersonSaved(this.id, this.name, this.age));
        return events;
    }

    @AfterDomainEventPublication //所有事件发布完成后调用,一般用来清空事件列表
    void callbackMethod() {
       domainEvents().clear(); 
    }
}

当Repository每一次调用save方法时,领域事件都会被发布。

我们的领域事件定义:

import lombok.Value;
@Value
public class PersonSaved {
    private Long id;
    private String name;
    private Integer age;
}

我们现在定义另外一个聚合根,为雇员(Employee),它和Person是一一对应的关系,但是多了公司的信息。基于设计小聚合的原则,我们没有给他们配置@OneToOne,而是当Person保存成功后发布领域事件PersonSaved,在事件监听的位置我们在另外一个事务中新建对应的Employee。小聚合的另外一个好处就是将事务边界变小从而有更快的速度和更好的性能。

新的雇员聚合:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class Employee {
  	@Id
    private Long id;
    private String name;
    private Integer age;
    @Embedded
    private Company company;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Embeddable
public class Company {
    private String name;
    private String city;
}

聚合的Repository:

public interface EmployeeRepository extends JpaRepository<Employee, Long> {
   List<Employee> findByName(String name);
}

领域发送的事件是Spring事件,我们可以使用@EventListener来接受,Spring Data给我们提供了专门的事务监听注解@TransactionalEventListener,它组合了@EventListener

@Component
public class DomainEventListener {

    private EmployeeRepository employeeRepository;

    public DomainEventListener(EmployeeRepository employeeRepository) {
        this.employeeRepository = employeeRepository;
    }

    @Async //1
    @TransactionalEventListener
    public void handlePersonSavedEvent(PersonSaved personSaved){
        Company company = new Company("某某公司", "hefei");
        Optional<Employee> employeeOptional = employeeRepository.findById(personSaved.getId());
        employeeOptional.ifPresent(employee -> { //2
            employee.setName(personSaved.getName());
            employee.setAge(personSaved.getAge());
          	employeeRepository.save(employee);
            return;
        });
        employeeRepository.save(new Employee(personSaved.getId(), personSaved.getName(), personSaved.getAge(), company));//3
    }
}
  1. 使用@Async注解让处理在另外一个线程处理;需要在配置类启用异步支持@EnableAsync

    @SpringBootApplication
    @EnableAsync
    public class LearningSpringDataJpaApplication {}
    
  2. 若存在则更新雇员;

  3. 若不存在则保存新的雇员。

    扫描二维码关注公众号,回复: 11565977 查看本文章

执行检验代码:

@Bean
CommandLineRunner domainEvents(PersonRepository personRepository,
                        EmployeeRepository employeeRepository){
   return args -> {
      Address address = new Address("nanjing","Jiangsu");
      Collection<Child> children = Arrays.asList(new Child("xxxx", Gender.FEMALE));
      Person savedPerson = personRepository.save(new Person("wwww", 33, address, children));
      Thread.sleep(100); //监听是在异步线程执行的,所以需等待
      List<Employee> employees1 = employeeRepository.findByName("wwww");
      employees1.forEach(System.out::println);
      savedPerson.setName("wwwww");
      personRepository.save(savedPerson);
     	Thread.sleep(100);
      List<Employee> employees2 = employeeRepository.findByName("wwwww");
      employees2.forEach(System.out::println);
   };
}

在这里插入图片描述

新书推荐:

我的新书《从企业级开发到云原生微服务:Spring Boot 实战》已出版,内容涵盖了丰富Spring Boot开发的相关知识
购买地址:https://item.jd.com/12760084.html
在这里插入图片描述

主要包含目录有:

第一章 初识Spring Boot(快速领略Spring Boot的美丽)
第二章 开发必备工具(对常用开发工具进行介绍:包含IntelliJ IDEA、Gradle、Lombok、Docker等)
第三章 函数式编程
第四章 Spring 5.x基础(以Spring 5.2.x为基础)
第五章 深入Spring Boot(以Spring Boot 2.2.x为基础)
第六章 Spring Web MVC
第七章 数据访问(包含Spring Data JPA、Spring Data Elasticsearch和数据缓存)
第八章 安全控制(包含Spring Security和OAuth2)
第九章 响应式编程(包含Project Reactor、Spring WebFlux、Reactive NoSQL、R2DBC、Reactive Spring Security)
第十章 事件驱动(包含JMS、RabbitMQ、Kafka、Websocket、RSocket)
第11章 系统集成和批处理(包含Spring Integration和Spring Batch)
第12章 Spring Cloud与微服务
第13章 Kubernetes与微服务(包含Kubernetes、Helm、Jenkins、Istio)
多谢大家支持。

猜你喜欢

转载自blog.csdn.net/wiselyman/article/details/106563016