[Spring] 스프링 이벤트

안드로이드를 공부하면서 알게 된 이벤트 처리는 스프링에서도 가능하다.

Spring에서 이벤트 처리가 궁금해서 정리/공부를 하게 되었습니다.

이벤트란 무엇입니까?

이벤트는 사용자 또는 프로그램 코드에 의해 트리거될 수 있는 이벤트입니다.

어떤 메시지

봄에 객체 간의 느슨한 결합을 통해 애플리케이션 유연성 및 확장성을 향상시키는 기능!

이벤트 기간

  • 이벤트 핸들러
    • 이벤트 핸들러
    • 이벤트가 발생할 때 실행할 코드를 구현하는 클래스입니다.

  • 이벤트 리스너
    • 이벤트 감지기
    • 이벤트 인식 및 처리
    • 이벤트 발생 시 이벤트를 처리하려면 이벤트 핸들러를 이벤트 리스너로 이벤트 소스에 연결해야 합니다.

봄 이벤트 사용 방법

  • ApplicationEvent 클래스 및 ApplicationListener 인터페이스를 통해 노출됩니다.

    • ApplicationListener 인터페이스를 구현한 bean이 context에서 제공될 때,
    • ApplicationEvent가 ApplicationContext로 전송될 때마다****
    • 이 컨테이너로 알림이 전송됩니다!
      !
      • 옵저버 디자인 패턴

Spring에서 제공하는 표준 이벤트

  1. ContextRefreshedEvent
    • ApplicationContext가 초기화되거나 업데이트될 때
  2. 컨텍스트 시작 이벤트
    • ApplicationContext가 시작될 때
  3. ContextStoppedEvent
    • ApplicationContext가 종료될 때
  4. ContextClosedEvent
    • 인터페이스의 close() 메서드를 사용하거나
    • ApplicationContext가 JVM 종료 후크를 통해 닫힐 때
  5. RequestHandledEvent
    • HTTP 요청이 처리되었음을 모든 Bean에 알리는 웹 전용 이벤트입니다.

  6. ServletRequestHandledEvent
    • 서블릿 관련 컨텍스트 정보를 추가하는 RequestHandledEvent의 하위 클래스

커스텀(커스텀) 애플리케이션 이벤트

ApplicationEvent 기본 클래스 확장의 예

public class BlockedListEvent extends ApplicationEvent {
	private final String address;
	private final String content;

	public BlockedListEvent(Object source, String address, String content) {
    super(source);
    this.address = address;
    this.content = content;
	}
// accessor and other methods...
}

맞춤형 애플리케이션 이벤트 사용 방법

  • ApplicationEventPublisher에서 publishEvent() 메서드를 호출합니다.

    • 일반적으로 ApplicationEventPublisherAware를 구현하는 클래스(EmailService)를 만듭니다.

    • 스프링 빈으로 등록
public class EmailService implements ApplicationEventPublisherAware {

    private List<String> blockedList;
    private ApplicationEventPublisher publisher;

    public void setBlockedList(List<String> blockedList) {
        this.blockedList = blockedList;
    }

    public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void sendEmail(String address, String content) {
        if (blockedList.contains(address)) {
            publisher.publishEvent(new BlockedListEvent(this, address, content));
            return;
        }
        // send email...
    }
}
  • Spring 컨테이너는 EmailService가 ApplicationEventPublisherAware를 보낼 수 있도록 합니다.

    알아 차리고
  • **setApplicationEventPublisher()**를 자동으로 호출
    • Spring 컨테이너에 전달되는 매개변수
  • 애플리케이션 컨텍스트와의 상호 작용은 ApplicationEventPublisher 인터페이스를 통해 수행됩니다.

public class BlockedListNotifier implements ApplicationListener<BlockedListEvent> {
	private String notificationAddress;

	public void setNotificationAddress(String notificationAddress) {
	    this.notificationAddress = notificationAddress;
	}

	public void onApplicationEvent(BlockedListEvent event) {
	    // notify appropriate parties via notificationAddress...
	}
}
  • 맞춤 신청 이벤트 리셉션에게
  • ApplicationListener를 구현하는 클래스를 생성하고 Spring bean으로 등록
<bean id="emailService" class="example.EmailService">
    <property name="blockedList">
        <list>
            <value>[email protected]</value>
            <value>[email protected]</value>
            <value>[email protected]</value>
        </list>
    </property>
</bean>

<bean id="blockedListNotifier" class="example.BlockedListNotifier">
    <property name="notificationAddress" value="[email protected]"/>
</bean>

주석 기반 이벤트 리스너

이벤트 리스너는 모든 관리 빈 메서드에서 @EventListener 주석으로 등록할 수 있습니다.

재작성된 BlockedListNotifier

public class BlockedListNotifier {
	private String notificationAddress;

	public void setNotificationAddress(String notificationAddress) {
	   this.notificationAddress = notificationAddress;
}

	@EventListener
	public void processBlockedListEvent(BlockedListEvent event) {
    // notify appropriate parties via notificationAddress...
	}
}

@EventListener와 함께

  • 여러 이벤트를 수신해야 하거나
  • 매개변수 없이 메서드를 정의하는 데에도 사용할 수 있습니다.

예시

@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
public void handleContextStart(){
	//..	
}

특정 이벤트에서 실제로 메서드를 호출하려면

일치해야 하는 SpEL 표현식을 정의하는 주석의 조건 속성을 사용하여

추가 런타임 필터링(content 속성이 my-event와 같은 경우에만 호출)

@EventListener(condition = "#blEvent.content == 'my-event'")
public void processBlockedListEvent(BlockedListEvent blEvent) {
    // notify appropriate parties via notificationAddress...
}

참조 기사
Spring Boot에서 이벤트 사용→ 왜 이벤트를 사용해야 하는지, 어떤 상황에서 잘 활용할 수 있는지 잘 설명된 글
(Spring) Spring 이벤트를 사용하여 서비스 간의 종속성 제거 → 예제 코드로 잘 정리됨