본문 바로가기
개발/Spring FW

Spring에서 ApplicationEvent 처리하기

by Devsong26 2023. 11. 29.

Spring Framework의 `ApplicationEvent` 클래스는 Spring의 이벤트 발행 및 처리 메커니즘의 핵심입니다. 이 메커니즘을 통해 애플리케이션 내에서 이벤트를 발행하고, 이를 처리하는 리스너들을 등록할 수 있습니다. `ApplicationEvent`와 관련된 기능은 애플리케이션의 결합도를 낮추고, 코드의 모듈화를 증진시키는 데 유용합니다.

 

 

ApplicationEvent 클래스

  • `ApplicationEvent`는 Java의 `java.util.EventObject`를 확장한 클래스입니다.
  • Spring 4.2부터는 `ApplicationEvent`를 상속받지 않고, 어떠한 객체도 이벤트로 발행할 수 있습니다.

 

 

이벤트 발행

  • 이벤트는 `ApplicationEventPublisher` 인터페이스를 통해 발행됩니다. 이 인터페이스는 보통 Spring의 `ApplicationContext`에 의해 제공됩니다.
  • `publishEvent` 메소드를 사용하여 이벤트를 발행할 수 있습니다.

 


이벤트 리스닝

  • 이벤트를 수신하기 위해 `ApplicationListener` 인터페이스를 구현하는 리스너를 만들 수 있습니다.
  • Spring 4.2 이후부터는 `@EventListener` 어노테이션을 사용하여 메소드 레벨에서 이벤트 리스너를 쉽게 구현할 수 있습니다.

 


이벤트의 장점

  • 결합도 감소
    • 이벤트 발행자와 리스너 간의 결합도가 낮아집니다. 이벤트 발행자는 리스너의 구체적인 구현을 몰라도 됩니다.
  • 유지보수성 향상
    • 이벤트 기반의 코드는 유지보수하기 쉽고, 변경에 대한 영향을 최소화합니다.
  • 비동기 처리
    •  @EventListener 가 적용된 이벤트 리스너는 동기적으로 수행됩니다.
    •  `@Async` 어노테이션을 사용하여 이벤트를 비동기적으로 처리할 수 있습니다.

 


주의사항

  • 트랜잭션 관리
    • 이벤트 리스너 내에서 수행되는 동작이 트랜잭션에 영향을 주지 않도록 주의해야 합니다.
  • 성능 고려
    • 많은 수의 이벤트 또는 복잡한 이벤트 처리 로직은 시스템의 성능에 영향을 줄 수 있습니다.

 


Spring의 `ApplicationEvent`는 애플리케이션 내에서 이벤트 기반 프로그래밍을 구현하는 데 매우 유용한 메커니즘을 제공합니다.

 

 


 

실습

 

 

이벤트 처리 순서는 다음과 같습니다.

  • ApplicationEvent 객체를 생성하여 ApplicationEventPublisher를 통해 발행합니다.
  • @EventListener가 지정된 메서드에서 ApplicationEvent를 소비합니다.

 

 

이벤트 클래스 정의

import lombok.Getter;
import org.springframework.context.ApplicationEvent;

import java.util.Arrays;
import java.util.Objects;

@Getter
public class CustomEvent extends ApplicationEvent {

    private final String eventType;
    private final Object object;

    private CustomEvent(String eventType, Object object){
        super(object);
        this.eventType = eventType;
        this.object = object;
    }

    public static CustomEvent of(String eventType, Object object){
        Arrays.asList(eventType, object).forEach(Objects::requireNonNull);
        
        return new CustomEvent(eventType, object);
    }

}

 

 

이벤트 퍼블리셔 정의

import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class CustomEventPublisher {

    private final ApplicationEventPublisher eventPublisher;

    public void publish(String eventType, Object object){
        eventPublisher.publishEvent(CustomEvent.of(eventType, object));
    }

}

 

 

이벤트 리스너 정의

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class CustomEventConsumer {

    private final Logger log = LoggerFactory.getLogger(CustomEventConsumer.class);
	
    @Async
    @EventListener
    public void handleCustomEvent(CustomEvent event) {
        log.info("EventType >> " + event.getEventType() + " , Object >> " + event.getObject());
    }

}

 

 

@EnableAsync 적용

@SpringBootApplication
@EnableAsync
public class DemoApplication {
   ...
}

 

 

테스트 코드

@SpringBootTest
@ActiveProfiles("dev")
@ExtendWith(SpringExtension.class)
public class EventTester {

    @Autowired
    CustomEventPublisher customEventPublisher;

    @Test
    public void test(){
        final String eventType = "TEST-EVENT-TYPE";
        final String object = "TEST-OBJECT";

        customEventPublisher.publish(eventType, object);
    }

}

 

 

'개발 > Spring FW' 카테고리의 다른 글

[Spring FW] Filter  (0) 2023.12.10
[Spring FW] Interceptor  (0) 2023.12.09
스프링 트랜잭션  (0) 2023.11.26
Feign Client  (2) 2023.11.25
JPA N+1 문제  (0) 2023.11.17