Spring/스프링 기본

[Spring] 스프링 이벤트 처리(Spring Event Processing) - 1탄 : 개요

공대키메라 2022. 7. 28. 22:32

최근에 Spring Security관련 내용을 공부하다가 Spring에서 Event를 다루는 것이 있기에

 

궁금해서 이번 장에서 공부하려고 한다. 

 

참고한 내용은 다음과 같다.

 

출처:

https://www.baeldung.com/spring-events

https://www.youtube.com/watch?v=xkWTO5M51FA&t=256s&ab_channel=SeleniumExpress

https://www.javadevjournal.com/spring/spring-events/

 

후에 올 예시들은 위 출처중에 youtube 영상을 많이 참조했다. 필자 키메라는 코드를 약간만 변형한 것이니 이해 바랍니다 꾸벅

 

1. 이벤트 처리가 무엇인가?

이벤트를 생각해보면 너무 단순하다.

 

현재 무엇인가 일어나는 일을 이벤트라고 우리는 이야기한다. 

 

그러한 일상적 의미의 이벤트 말고도, UI 화면을 구성할 때, input tag에 이벤트를 준다던지,

 

버튼을 클릭시 이벤트를 준다던지, 이렇게 우리가 흔히 이야기한다. 

 

Spring 에서 제공하는 Spring Event 는 Server Side Event 로 

 

이벤트 처리(Event Processing)은 프로그래밍의 하나의 느슨하게 연결시키는 방식이다. 

 

이벤트 처리에 포함된 네 개의 컴포넌트들이 있다. (Source, Event, Listener, Handler)


그런데 필자는 이러한 정보를 읽다가 든 생각인데... 왜 느슨하게 연결하는 방식이 필요하지? 하는 생각이 들었다.

 

spring 에서는 DI, IoC가 생겨난 이유는 결국 각각 Spring Container에 의해 관리되는 class들을 bean이라고 하는데, 

 

이 class들을 결합성, 즉 직접 내부에서 생성해서 받아 사용하는 방식으로 코드를 작성하는 대신에, Container에서 관리되는 bean을 사용하게 되어서 의존성이 역전되었다! 해서 Dependency Injection 이라고 한다. 

 

그래... 거기까지는 알겠어... 

 

그런데 느슨하게 연결하는 방식으로 이미 있는것 같은데... 

 

어째서 Spring Event 같은 기능이 필요할까? 

 

이에 대한 해답을 찾기 위해 여정(윤여정)을 시작할 것이다. 

 

2. 예시를 통해 본 Spring Event - 필요성

 

 

이것을 위해 필자는 연습 코드를 작성했다. 프로젝트 구조든 위와 같다. 

 

예시는 요즘 이상한 변호사 우영우가 매우 인기가 많으니, 이것을 모티브로 한 번 구성해보도록 하겠다.

(스위스기러기별똥별토마토우영우)

 

NetFlixPublisher.java

package springevent.springevent.publisher;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import springevent.springevent.listener.MsgListener;
import springevent.springevent.listener.ShaneListener;

@Component
public class NetFlixPublisher {
    @Autowired
    private MsgListener msgListener;
    public void streamWooYoungWoo(String episodeNo){
        System.out.println("Woo Young Woo : starting episode : " + episodeNo);
        msgListener.watchWooYoungWoo(episodeNo);
    }

}

 

우선 NetFlix에서 제작한 드라마를 우리가 본다고 가정하자.

 

NetFlix에서는 드라마를 제작한 후 이것을 공개(publish)해야한다. 

 

그러면 publish 한 드라마를 개개인의 계정으로 접근해서 시청하는 것이다. 

 

우선 키메라(이니셜 msg)가 NetFlix의 우영우를 시청할 것이다. 

 

그러면 NexFliex에는 나를 구독자로 등록하겠지?

 

구독자로 등록이 되면 나는 그냥 그것을 보면 되는 것이다. listener로서 말이다.

 

MsgListener.java

package springevent.springevent.listener;

import org.springframework.stereotype.Component;

@Component
public class MsgListener {
    public void watchWooYoungWoo(String epNo) {
        System.out.println("Msg : started watching Woo Young Woo");
        System.out.println("Msg : playing... : " + epNo);
    }
}

 

그리고 Config 파일을 생성해서 자동으로 bean으로 등록되도록 하겠다.

 

AppConfig.java

package springevent.springevent.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("springevent")
public class AppConfig {}

여기서 잠깐! Component, Configuration, ComponentScan에 대해 잘 모르겠다면, 

 

필자가 전에 공부한 블로그를 참고해서 이해하는데 도움이 되었으면 한다. (궁금하면 여기 🤣🤣 클릭!)


App.java

package springevent.springevent.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import springevent.springevent.config.AppConfig;
import springevent.springevent.publisher.NetFlixPublisher;

public class App {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        NetFlixPublisher bean = context.getBean("netFlixPublisher", NetFlixPublisher.class);
        bean.streamWooYoungWoo("EP - 004");
    }
}

 

자! 이제 그러면 필자 키메라는 우영우를 드디어 볼 수가 있다!

 

다음 그림에서 출력 결과를 볼 수 있다. 

 

 

와우! 우영우 너무 재미있어!

 

그런데... 다른 사람이 우영우가 너무 재미있는 나머지 보고싶은 사람이 늘어나버린 것이다. 

 

그러면... 필자 키메라처럼 구독 등록하고, 개인의 기기에서 볼 수 있도록 세팅을 해야한다. 

 

ShaneListener..java

package springevent.springevent.listener;

import org.springframework.stereotype.Component;

@Component
public class ShaneListener {
    public void watchWooYoungWoo(String epNo) {
        System.out.println("Shane : started watching Woo Young Woo");
        System.out.println("Shane : playing... : " + epNo);
    }
}

 

NetFlixPublisher.java - modified

package springevent.springevent.publisher;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import springevent.springevent.listener.MsgListener;
import springevent.springevent.listener.ShaneListener;

@Component
public class NetFlixPublisher {

    @Autowired
    private MsgListener msgListener;
    @Autowired
    private ShaneListener shaneListener;
    public void streamWooYoungWoo(String episodeNo){
        System.out.println("Woo Young Woo : starting episode : " + episodeNo);
        msgListener.watchWooYoungWoo(episodeNo);
        shaneListener.watchWooYoungWoo(episodeNo);
    }

}

 

위처럼 코드를 구성하고 다시 App 파일의 main 메소드를 실행하면 다음과 같이 나온다. 

 

 

여기서 우리는 쎄한 느낌을 받을 것이다.

 

이런식으로 하다가는 뭔가 아닌걸 대부분 눈치챌 것이다. 구독자가 늘 때 마다, Listener파일을 생성하고, 일일이 publisher에 추가를 해줘야 하니 쒸이익... 분노가 치민다!

 

이 문제를 해결하기 위해서는 굉장히 많이 들어본 디자인 패턴을 도입하면 된다.

 

그것은 감시자(Observer)패턴이다!

(옵저버 패턴이 궁금한 분은 필자가 작성한 내용을 참고하면 좋다. 궁금하면 여기 😂😂클릭!! 🤣🤣)

 

3. Spring Event vs Method Call

우선 여러 사이트를 찾던 중 Spring Event 와 Method Call에 대한 차이점을 찾았다.

 

다른 모듈들과 communicate할 때, 우리는 Spring application에서 작동하는 다음 옵션들을 가진다. 

 

     1. 전통적인 메소드 호출 사용(Using traditional method call)

 

     2. Spring framework event 시스템 사용(Using Spring framework events system)

 

메소드 호출은 전통적이고 또한 의사소통하는 동안 가장 흔한 방식이다. 

 

여러 경우에 다음 단계로 넘어가기 전에, 다른 컴포넌트들로 부터 응답이 필요한 곳에서 메소드를 호출해야할 필요가 있을지도 모른다. 

(예를 들어, 체크아웃동안 신용 카드 정보를 검증하는것이 있다. 우리는 불명확한 신용 카드를 가지고 주문을 할 수 없다. 또는 돈이 없어도 말이다) 

 

반면에 모든 관심있는 모임들은 행동할 수 있도록 구체적인 단계에서 모든 모임들에게 이벤트들이 그 과정중에 발생한다.

 

스프링 이벤트들은 현재 thread를 막는 것 없이 다른 thread에서 처리를 넘기길 원할때 좋은 선택지이다. 

 

여기 events가 좋은 경우가 있다. 

 

     1. 주문 장소에 대해 고객에게 이메일을 보내는 것

 

     2. 주문이 배송중일 때 알람을 보내는 것

 

 Spring framework는 우리 요구사항에 대해 다양한 spring event 기초를 생성하기 위한 옵션들을 제공한다. 

 

또한, 필요하다면 custom event를 생성하도록 유연성을 제공한다. 

 


이번 시간에는 이벤트 처리가 무엇인지 생각해보았고, Spring Event 가 필요한 이유에 대해 대략적으로 알아보았다.

 

다음 시간에는 어떻게 문제를 해결할 지 알아보도록 하겠다.