스프링 데이터 JPA
3. 스프링 데이터 Common
본격적인 스프링 데이터 JPA 활용법을 학습하기에 앞서, ORM과 JPA에 대한 이론적인 배경을 학습합니다
포스팅 참조 정보
GitHub
공부한 내용은 GitHub에 공부용 Organizations에 정리 하고 있습니다
해당 포스팅에 대한 내용의 GitHub 주소
실습 내용이나 자세한 소스코드는 GitHub에 있습니다
포스팅 내용은 간략하게 추린 핵심 내용만 포스팅되어 있습니다
해당 포스팅 참고 인프런 강의
실습 환경
- Java Version: Java 11
- SpringBoot Version: 2.1.2.RELEASE
9. 스프링 데이터 Common: 도메인 이벤트
도메인(Entity 클래스) 관련 변화를 이벤트를 발생시키기
도메인을 하는 이벤트 리스너가 도메인 Entity 클래스의 변화를 감지하고 이벤트 기반의 프로그래밍을 할 수 있음
스프링 프레임워크의 이벤트 관련 기능
- 스프링을 사용하는 모든 프로젝트에는 이벤트를 만들어서 Publishing 하고 Listening 하는 기능이 내재되어있음
- ApplicationContext가 이벤트 Publisher 임
- BeanFactory, EventPublisher 인터페이스를 상속 받았음
ApplicationContext extends ApplicationEventPublisher
- 이벤트: extends ApplicationEvent
- 리스너
implements ApplicationListener<E extends ApplicationEvent>
@EventListener
스프링 데이터의 도메인 이벤트 Publisher
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#core.domain-events
스프링 데이터가 자동 Publishing 기능을 제공 쌓여있던 이벤트들을 save하는 순간 다 보내줌
@DomainEvents
: 이벤트를 모아놓는 곳@AfterDomainEventPublication
: 이벤트를 자동으로 비워주는 메서드
도메인 이벤트 실습
PostPublishedEvent 클래스 생성
이벤트를 발생시키는 곳이 post 이고 이벤트를 받는 리스너 쪽에서 어떤 post에 대한 이벤트였는지
post를 참조할 수 있도록 getter 추가
public class PostPublishedEvent extends ApplicationEvent {
private final Post post;
/**
* Create a new ApplicationEvent.
*
* @param source the object on which the event initially occurred (never {@code null})
*/
public PostPublishedEvent(Object source) {
super(source);
this.post = (Post) source;
}
public Post getPost() {
return post;
}
}
PostListner 클래스 생성
Post Event Listner 구현
public class PostListner implements ApplicationListener<PostPublishedEvent> {
@Override
public void onApplicationEvent(PostPublishedEvent event) {
System.out.println("-----------------");
System.out.println(event.getPost() + " is published!");
System.out.println("-----------------");
}
}
테스트 Config 구현
PostListner를 빈으로 등록해줌
@Configuration
public class PostRepositoryTestConfig {
@Bean
public PostListener postListner() {
return new PostListener();
}
}
테스트 로직 구현
@Import(PostRepositoryTestConfig.class)
로 PostListener 클래스를 빈 으로 등록- 테스트가 실행되면 테스트에서는 event를 Publish 했을 때 PostListener이 잡아서 메세지를 출력
- 슬라이싱 테스트라서 DataJpa 관련된 빈들 만 등록되므로
@Import
를 사용해 별도로PostListener
을 빈으로 등록
@RunWith(SpringRunner.class)
@DataJpaTest
@Import(PostRepositoryTestConfig.class)
public class PostRepositoryTest {
@Autowired
ApplicationContext applicationContext;
@Test
public void event() {
Post post = new Post();
post.setTitle("event");
PostPublishedEvent event = new PostPublishedEvent(post);
applicationContext.publishEvent(event);
}
}
AbstractAggregationRoot
스프링 데이터에 이미 위의 어노테이션이 적용되어 이벤트 모아두는 곳, 이벤트 비우는 곳이 구현되어 있음
이벤트를 직접 만들고 이벤트를 Publishing 할 필요가 없음
extends AbstractAggregationRoot<E>
- 현재는
save()
할 때만 발생save
할때 이벤트를 만들어 넣으면 됨save
할때 자동으로 AbstractAggregationRoot를 통해 domainEvents 에 모아져있던 이벤트를 다 발생시킴- 그러면 만들어 두었던 EventListener가 동작함
- 직접 이벤트를 던져주는 코드가 사라짐
AbstractAggregationRoot를 통해 이벤트 등록
아래와 같이 Post 클래스 AbstractAggregateRoot를 상속받아서 구현
상속받아서 이벤트를 자동으로 등록해주는 로직을 구현해주면 별도의 이벤트 등록 코드를 구현하지 않아도 이벤트가 자동으로 등록됨
@Entity
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;
}
}
테스트 로직
아래와 같이 save 할때 post.publish()
를 호출하면 이벤트가 호출되어 이벤트 리스너가 동작함
@Test
public void crud() {
Post post = new Post();
post.setTitle("hibernate");
// save 하기 전에 postRepository.contains안에 post가 들어있는지 검증
// post가 들어있지 않은 Transient 상태
assertThat(postRepository.contains(post)).isFalse();
postRepository.save(post.publish());
// post가 들어있는 Persist 상태
assertThat(postRepository.contains(post)).isTrue();
postRepository.delete(post);
postRepository.flush();
}
PostListener에서 @EventListener
사용
둘다 스프링 프레임워크가 제공해주는 기능임
기존 로직
public class PostListener implements ApplicationListener<PostPublishedEvent> {
@Override
public void onApplicationEvent(PostPublishedEvent event) {
System.out.println("-----------------");
System.out.println(event.getPost() + " is published!");
System.out.println("-----------------");
}
}
@EventListener
적용 로직
반드시 PostListener이 빈으로 등록되어 있어야함
public class PostListener {
@EventListener
public void onApplicationEvent(PostPublishedEvent event) {
System.out.println("-----------------");
System.out.println(event.getPost() + " is published!");
System.out.println("-----------------");
}
}
PostListener 클래스 안만들고 TestConfig 파일에 직접등록
아래와 같이 PostListener 클래스를 만들지 않고 직접 TestConfig에 등록해도됨
@Configuration
public class PostRepositoryTestConfig {
@Bean
public ApplicationListener<PostPublishedEvent> postListener() {
return new ApplicationListener<PostPublishedEvent>() {
@Override
public void onApplicationEvent(PostPublishedEvent event) {
System.out.println("-----------------");
System.out.println(event.getPost() + " is published!");
System.out.println("-----------------");
}
};
}
}
'개발강의정리 > Spring' 카테고리의 다른 글
[스프링 데이터 JPA] 3-11. 스프링 데이터 Common: Web 1부: 웹 지원 기능 소개 (0) | 2019.11.23 |
---|---|
[스프링 데이터 JPA] 3-10. 스프링 데이터 Common: QueryDSL (0) | 2019.11.23 |
[스프링 데이터 JPA] 3-8. 스프링 데이터 Common: 기본 리포지토리 커스터마이징 (0) | 2019.11.23 |
[스프링 데이터 JPA] 3-7. 스프링 데이터 Common: 커스텀 리포지토리 (0) | 2019.11.23 |
[스프링 데이터 JPA] 3-6. 스프링 데이터 Common: 비동기 쿼리 (0) | 2019.11.23 |
댓글