Altiora Petamus

[Spring] ApplicationEventPublisher 를 사용한 Event 처리 본문

Java/Spring Framework

[Spring] ApplicationEventPublisher 를 사용한 Event 처리

Haril Song 2021. 5. 17. 10:36

ApplicationEventPublisher

  • Spring의 ApplicationContext가 상속하는 인터페이스 중 하나
  • Design Pattern 중 하나인 옵저버 패턴의 구현체

 

이벤트를 발생하는 Publisher와 이를 감시하는 Observer(or Subscriber) 사이의 결합도를 낮추면서 이벤트를 Observer에게 전달하고 싶을 때 사용하게 된다.

 

 

사용

파일 업로드를 시도한다고 가정할 때, 성공과 에러를 구분해서 이벤트를 감지하고 결과를 간단한 RESTful API를 사용하여 내려주도록 해보자.

 

Event

import lombok.Builder;
import lombok.Getter;

import java.util.Map;
import java.util.UUID;

@Getter
@Builder
public class FileEvent {
    private String eventId;
    private String type;
    private Map<String, Object> data;

    public static FileEvent toCompleteEvent(Map data) {
        return FileEvent.builder()
                .eventId(UUID.randomUUID().toString())
                .type(EventType.COMPLETED.name())
                .data(data)
                .build();
    }

    public static FileEvent toErrorEvent(Map data) {
        return FileEvent.builder()
                .eventId(UUID.randomUUID().toString())
                .type(EventType.ERROR.name())
                .data(data)
                .build();
    }
}

Spring 4.2 이후에는 Event에서 AppplicationEvent 를 상속받을 필요가 없어졌다. 4.2 이후의 이벤트 처리는 POJO Java 가 된다. 이러한 구현 방식은 소스 코드에 spring 코드가 들어가지 않도록 하는 비침투성 철학과 일치한다.

결과적으로 개발자는 의존성 같은 고려없이 더 편하게 테스트 할 수 있게하고 코드를 유지보수하기 쉽게 한다.

 

Publisher

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

@Component
@RequiredArgsConstructor
public class FileEventPublisher {

    private final ApplicationEventPublisher applicationEventPublisher;

    public void notifyComplete(FileEvent fileEvent) {
        applicationEventPublisher.publishEvent(fileEvent);
    }

    public void notifyError(FileEvent fileEvent) {
        applicationEventPublisher.publishEvent(fileEvent);
    }
}

ApplicationEventPublisherpublishEvent() 메소드를 호출해서 이벤트를 발생시킬 수 있다. publishEvent() 는 자바의 최상위 클래스인 Object를 받을 수 있으므로 파라미터로 전달하는 타입을 신경쓰지 않아도 된다.

 

Listener

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class FileEventListener {

    @EventListener
    public void onFileEventHandler(FileEvent fileEvent) {
        log.info("fileEvent receive type : {} data : {}", fileEvent.getType(), fileEvent.getData());
    }
}

FileEventListener는 스프링이 누구에게 이벤트를 전달할지 알아야하기 때문에 빈으로 등록되어야 하고 @Component를 사용해서 등록한다.

@EventListener 어노테이션을 통해 Handler를 구현한다. 정해진 이벤트가 발생하게 되면 이 어노테이션이 달린 메소드가 실행되면서 로그가 찍히게 된다.

 

 

FileService

@Slf4j
@Service
@RequiredArgsConstructor
public class FileService {

    private final FileEventPublisher fileEventPublisher;

    public void fileUpload(Map<String, Object> data) {
        try {
            log.info("파일 복사 완료");
            log.info("DB 파일 메타 정보 저장 완료");
            FileEvent completeEvent = FileEvent.toCompleteEvent(data);
            fileEventPublisher.notifyComplete(completeEvent);
        } catch (Exception e) {
            log.error("file upload fail", e);
            FileEvent errorEvent = FileEvent.toErrorEvent(data);
            fileEventPublisher.notifyError(errorEvent);
        }
    }
}

 

 

Controller

@RestController
@RequiredArgsConstructor
public class FileController {

    private final FileService fileService;

    @GetMapping("/upload/image")
    public ResponseEntity fileUpload() {
        Map<String, Object> data = new HashMap<>();
        data.put("userId", "홍길동");
        data.put("type", "webp");
        data.put("fileSize", 5);

        fileService.fileUpload(data);

        return ResponseEntity.ok("success");

    }
}

 

로그 확인

스프링을 실행시키고 @GetMapping 으로 명시해준 url 로 접속해보자.

 

이벤트가 정상적으로 발생하며 의도대로 동작하는 것을 알 수 있다.

 

 

 

Reference

 

[Spring] ApplicationEventPublisher를 이용한 이벤트 프로그래밍

[Spring] ApplicationEventPublisher를 이용한 이벤트 프로그래밍 ApplicationEventPublisher는 Spring의 ApplicationContext가 상속하는 인터페이스 중 하나이다. 옵저버 패턴의 구현체로 이벤트 프로그래밍..

atoz-develop.tistory.com

 

Spring - IoC 컨테이너의 기능 - 4 (ApplicationEventPublisher 란?)

IoC 컨테이너의 기능 중 하나인 ApplicationEventPublisher에 대해서 알아보겠습니다 1. ApplicationEvnetPublisher가 뭐죠? IoC 컨테이너의 기능 중 하나인 ApplicationEventPublisher 에 대해서 알아보겠습니다...

galid1.tistory.com

 

'Java > Spring Framework' 카테고리의 다른 글

다양한 HTTP Mapping 1  (0) 2021.07.28
in-memory DB 구현  (0) 2021.06.30
Spring Security 사용하기 1  (0) 2021.06.26
Spring Security란?  (0) 2021.06.19
[Spring] AOP 활용하기  (0) 2021.05.20