꿀똥벌레
꿀똥벌레 개발 블로그
꿀똥벌레
전체 방문자
오늘
어제
  • 분류 전체보기 (90)
    • JAVA (17)
    • SPRING (14)
    • Elasticsearch (4)
    • GRADLE (2)
    • HTML, CSS (0)
    • JAVASCRIPT (0)
    • GIT (1)
    • Vue.js (1)
    • server (1)
    • Python (0)
    • IT리뷰 (0)
    • 인프라 (6)
    • IOS (21)
    • 디자인패턴 (20)
    • Kafka (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 엘라스틱서치
  • SWIFT
  • Index
  • 스프링 인테그레이션
  • Index Template
  • 인덱스 템플릿
  • persistence connection
  • spring
  • mappings
  • connectionRequestTimeout
  • persistent connection
  • maxConnTotal
  • ES
  • springintegration
  • java
  • elasticsearch
  • KEEPALIVE
  • maxConnPerRoute
  • spring integration
  • 스프링 인티그레이션

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
꿀똥벌레

꿀똥벌레 개발 블로그

SPRING

Spring Event

2021. 5. 27. 17:30

Spring Event

  • 특정 이벤트를 발행(publish) 하면, 해당 이벤트가 발행되기를 대기하고 있던 리스너가 실행된다.
  • 이벤트 발행 클래스와 리스너 클래스간 코드 의존성이 없다.
  • 리스너 실행을 비동기로 실행할 수 있다.

이벤트 클래스

public class CustomEvent extends ApplicationEvent {

  @Getter
  private String message;

  public CustomEvent(Object source, String message) {
    super(source);
    this.message = message;
  }
}
  • ApplicationEvent 를 상속받는다.
  • super 생성자를 반드시 실행해 줘야 한다.

이벤트 발행자(publisher) 클래스

@RequiredArgsConstructor
@Component
public class CustomEventPublisher {
  private final ApplicationEventPublisher publisher;

  public void publish(final String message) {
    System.out.println("publish custom event");
    CustomEvent event = new CustomEvent(this, message);
    publisher.publishEvent(event);
  }
}
  • 스프링의 publisher 클래스인 ApplicationEventPublisher 클래스를 이용해 이벤트를 발행한다.

이벤트 리스너 클래스

@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {
  @Override
  public void onApplicationEvent(CustomEvent event) {
    System.out.println("Received custom event" + event.getMessage());
  }
}

//동일한 기능을 어노테이션 기반으로 작성

@Component
public class CustomEventListener {

  @EventListener
  public void handleCustomEvent(CustomEvent event) {
    System.out.println("Received custom event" + event.getMessage());
  }
}

ApplicationListener 상속 방법

  • ApplicationListener 를 구현하여 작성한다.
  • 제네릭 타입에 받아들일 이벤트 타입을 넣는다.
  • onApplicationEvent 메소드를 오버라이드 하여 이벤트 발행시 받아들일 메소드를 작성한다.

어노테이션 기반 방법

  • @EventListener 어노테이션 하나만으로 작동 되므로 훨씬 간편하다.

Async 설정 추가

@Configuration
public class AsyncEventConfig {

  @Bean
  public ApplicationEventMulticaster simpleApplicationMultiCaster() {
    SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
    multicaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
    return multicaster;
  }
}

//어노테이션 기반

@EnableAsync
@SpringBootApplication
public class Application {
}

@Component
public class CustomEventListener {

  @EventListener
    @Async
  public void handleCustomEvent(CustomEvent event) {
    System.out.println("Received custom event" + event.getMessage());
  }
}

Configuration 설정 기반

  • 추가적으로 ApplicationEventMulticaster 빈을 생성해주며, async executor 를 추가해준다.

어노테이션 기반

  • async사용 설정을 위해 스프링부트 루트 클래스에 @EnableAsync 를 선언해준다.
  • 실행될 이벤트 리스너 메서드에 @Async를 적용해준다.

@DomainEvent 를 이용해 도메인에서 이벤트 발행

도메인 클래스

@Entity
public class CustomDomain {

  @Id
  @GeneratedValue
  private Long id;

  private int age;

  @Transient
  private final Collection<CustomEvent> customEvents = new ArrayList<>();

  @DomainEvents
  public Collection<CustomEvent> events() {
    return customEvents;
  }

  @AfterDomainEventPublication
  public void afterEventPublication() {
    customEvents.clear();
  }

  public void addAge() {
    this.age++;
    customEvents.add(new CustomEvent(this, "user age is " + age));
  }
}
  • 도메인의 addAge를 실행하는 경우 발행될 이벤트 목록에 하나의 이벤트를 추가한다.
  • @DomainEvents 어노테이션을 통해 이벤트가 담겨져 있는 컬렉션을 리턴한다.
  • @DomainEvents 가 달려있는 메소드는 Repository.save로 해당 도메인이 저장되는 때에 메소드가 실행되고, 리턴된 이벤트 목록이 스프링에 의해 발행된다.
  • @AfterDomainEventPublication 메소드는 repository.save() 실행시 등록 이벤트가 없더라도 실행된다.

Repository

@Repository
public interface CustomRepository extends JpaRepository<CustomDomain, Long> {
}

사용

public void test() {
    CustomDomain domain = customRepository.findById(1L)
                .orElseThrow(() -> new NullPointerException());
    domain.addAge();
    customRepository.save(domain);
  }

AbstractAggregateRoot 를 이용해 이벤트 발생

@Entity
public class CustomDomain extends AbstractAggregateRoot<CustomDomain> {

  @Id
  @GeneratedValue
  private Long id;

  private int age;

  @AfterDomainEventPublication
  public void afterEventPublication() {
    System.out.println("publish finish!@@@@@");
  }

  public void addAge() {
    this.age++;
    registerEvent(new CustomEvent(this, "user age is " + age));
  }
}
  • AbstractAggregateRoot를 상속 받고, registerEvent 로 이벤트를 등록 한다.
  • @AfterDomainEventPublication 메소드는 repository.save() 실행시 등록 이벤트가 없더라도 실행된다.
  • repository.save() 를 실행 해야 등록된 이벤트가 실행된다 (@Transactional 에 의한 변경감지로 저장은 실행되지 않음.)

'SPRING' 카테고리의 다른 글

Spring Batch FaultTolerance (장애 허용)  (0) 2021.12.13
Spring Envers 로 자동 이력 관리  (0) 2021.06.20
Spring 메소드 실행 실패시 재실행  (0) 2021.05.24
Spring Rest Docs 사용법  (0) 2021.05.02
Spring Batch  (0) 2021.04.28
    꿀똥벌레
    꿀똥벌레
    개발자 꿀똥벌레 입니다.

    티스토리툴바