[Spring JPA #15] 스프링 데이터 도메인 이벤트

2021. 3. 25. 23:44 Spring Data/Spring Data JPA

 

스프링 데이터 도메인 이벤트

 

  • 스프링 프레임워크에서는 주로 IoC 컨테이너에 접근하기 위한 ApplicationContext 인터페이스를 제공합니다. 
  • 이 ApplicationContext는 ApplicationEventPublisher를 상속받기 때문에 사용자가 정의한 이벤트나 스프링 프레임워크에서 미리 정의한 이벤트를 publish하는 기능도 제공하고 있습니다.
  • 사용자가 정의한 이벤트를 수신하기 위해서는 리스너를 정의하여 해당 클래스에 맞는 이벤트를 받아 처리하면 됩니다.

 

| 스프링 데이터 도메인 이벤트 예제

 

프로젝트 구조

├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── tutorial
│   │   │           └── springdatarepository
│   │   │               ├── AppRunner.java
│   │   │               ├── Post.java
│   │   │               ├── PostListener.java
│   │   │               ├── PostPublishedEvent.java
│   │   │               └── SpringDataRepositoryApplication.java
│   │   └── resources
│   │       └── application.properties

 

의존성 관리

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

 

소스 코드

@SpringBootApplication
public class SpringEventApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringEventApplication.class, args);
    }

}
@Entity
@Data
public class Post {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    @Lob
    private String content;

    @Temporal(TemporalType.TIMESTAMP)
    private Date created;
}
public class PostPublishedEvent extends ApplicationEvent {

    private final Post post;

    public PostPublishedEvent(Object source) {
        super(source);
        this.post = (Post) source;
    }

    public Post getPost() {
        return post;
    }
}

 

  • ApplicationEvent를 상속하여 Custom Event를 작성하였습니다. Post 객체를 받는 생성자와 저장된 Post 객체의 Getter만을 작성하였습니다.
@Component
public class PostListener implements ApplicationListener<PostPublishedEvent> {

    @Override
    public void onApplicationEvent(PostPublishedEvent event) {
        System.out.println("------------------------");
        System.out.println(event.getPost().getTitle() + " is published");
        System.out.println("------------------------");
    }
}
  • PostListener 는 PostPublishedEvent가 publish될 때 그 이벤트를 수신하여 출력하는 Event Listener입니다.

 

@Component
public class AppRunner implements ApplicationRunner {

    @Autowired
    ApplicationContext applicationContext;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        Post post = new Post();
        post.setTitle("POST EVENT");
        PostPublishedEvent event = new PostPublishedEvent(post);

        applicationContext.publishEvent(event);
    }
}
  • ApplicationContext의 구현체는 이벤트를 publish할 수 있는 기능을 제공합니다. 따라서 PostPublishedEvent를 ApplicationContext 인터페이스를 통하여 publish하면 그 이벤트가 위에서 작성한 PostListener에게 수신되는 것을 알 수 있습니다.

 

결과화면

------------------------
POST EVENT is published
------------------------

 

| 도메인 이벤트를 구현하기 위한 다양한 예제들

 

위 AppRunner에서 

Post post = new Post();
post.setTitle("POST EVENT");
PostPublishedEvent event = new PostPublishedEvent(post);

applicationContext.publishEvent(event);

 

PostPublishedEvent를 등록하고 publish하기 위한 구문을 다음과 같이 Post에 AbstractAggregateRoot 클래스를 확장하여 이 클래스에서 상속받은 registerEvent 메서드를 통해 이벤트를 등록하게 되면 위 구문을 더 간략하게 만들 수 있습니다.

 

소스 코드

@Entity
@Data
public class Post extends AbstractAggregateRoot<Post> {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    @Lob
    private String content;

    @Temporal(TemporalType.TIMESTAMP)
    private Date created;

    public Post publish() {
        this.registerEvent(new PostPublishedEvent(this));
        return this;
    }
}
  • AbstractAggregateRoot 클래스는 도메인 이벤트를 등록하고 publish 하는 기능을 제공합니다. 
  • 위 코드처럼 이벤트를 등록시키면 Repository 인터페이스에서 save 메서드를 호출할 시, AbstractAggregateRoot 안의 domainEvents을 통해 모아놓은 이벤트를 발생시킵니다.

 

@Component
public class PostListener {

    @EventListener
    public void onApplicationEvent(PostPublishedEvent event) {
        System.out.println("------------------------");
        System.out.println(event.getPost().getTitle() + " is published");
        System.out.println("------------------------");
    }
}
  • ApplicationListener를 상속받지 않고도 @EventListener 어노테이션을 통해 Event Listener를 등록할 수 있습니다.

 

https://www.inflearn.com/course/스프링-데이터-jpa



출처: https://engkimbs.tistory.com/827?category=772527 [새로비]