SpringBoot Background Thread 생성 (servlet 이용)

김명래·2023년 3월 7일
0

Event Listener

어떠한 이벤트가 발생하면 호출되어 처리하는 객체를 말한다.

Listner를 사용하기 위해서는 인터페이스를 구현하는 클래스를 만들어야한다.

Listener 인터페이스의 종류

ServletContextListener

웹 어플리케이션의 시작과 종료시 자동으로 발생되는 이벤트를 수행하기 위한 메소드를 정의한 인터페이스이다.

contextInitialized(ServletContextEvent sce) : void

웹 컨테이너가 처음 구동될 때 실행되는 메소드이다.

contextDestoryed(ServletContextEvent sce)

웹 컨테이너가 종료될 때 실행되는 메소드

ServletContextAttributeListener

컨테이너에 저장된 속성 값들의 변화가 있을 때 수행하기 위한 메소드를 정의한 인터페이스이다.

HttpSessionListener

HTTP 세션이 활성화 되거나 비활성화 되려할 때 혹은 속성 값들이 추가, 삭제, 변경될 경우 수행하기 위한 인터페이스 이다.

HttpSessionAttributeListener

HTTP 세션에 대한 속성 값이 변경되었을 경우 수행하기 위한 인터페이스

HttpSessionActivationListener

세션에 대한 내용이 새로 생성되어 세션이 활성화 되었을 때 발생하는 이벤트를 수행하기 위한 인터페이스

HttpSessionBindingListener

클라이언트의 세션 정보에 대한 바인딩이 이루어졌을 경우 감지되는 이벤트를 수행하기 위한 인터페이스

내가 개발하려는 것은 spring server가 실행될 때 fileWatch 기능이 있는 Thread 를 생성하여 백그라운드에 계속 남겨두는 것 이다.

즉, web application 실행 event를 받는 listner안에 thread 내용을 구현하면될 것 이다.

따라서 ServletContextListener interface를 구현한 class 를 생성할 것 이다.



import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.annotation.WebListener;
import lombok.extern.slf4j.Slf4j;

@WebListener
@Slf4j
public class FileWatch implements ServletContextListener, Runnable{
    private Thread thread;
    private boolean isShutdown = false;

    private ServletContext sc;


    public void startFileWatch(){
        if(thread == null)
            thread = new Thread(this, "Watch Thread");

        if(!thread.isAlive())
            thread.start();
    }


    @Override
    public void run() {
        Thread currentThread = Thread.currentThread();

        while(currentThread == thread && !this.isShutdown){
            try{
                log.info("file watch is running");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        log.info("fileWatch end");
    }

    @Override
    public void contextInitialized(ServletContextEvent sce) { // 생성자, 즉 web application 이 실행될때 실행된다.
        log.info("contextInitialized call");
        startFileWatch();
        ServletContextListener.super.contextInitialized(sce);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) { // 소멸자, web application이 삭제될 때 실행된다.
        log.info("contextDestroyed call");
        this.isShutdown = true;
        try {
            thread.join();
            thread = null;
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        ServletContextListener.super.contextDestroyed(sce);
    }
}

이후 servlet 컨테이너에 등록하기위해 applcation 실행 class에 ServletComponentScan Annotation을 사용한다.

@SpringBootApplication
@ServletComponentScan
public class NHNStorageApplication {

	public static void main(String[] args) {
		SpringApplication.run(Test.class, args);
//				.addApplicationListener(new ApplicationPidFileWriter());
	}

}

결론

다른 방법도 찾는도중
@PostConstruct annotation의 존재를 알았다.

@PostConstruct annotation

객체가 인스턴스화된 직후 서비스에 투입되기 전에 호출되어야 하는 클래스의 메서드를 표시하는 데 사용되는 Java 주석입니다. 개체를 사용하기 전에 필요한 초기화를 수행하기 위한 콜백 메서드로 자주 사용됩니다.

내겐 이 방법이 더 좋은것 같아서
Thread 는 @PostConstruct annotation 을 이용해 생성하기로 결론냈다.

profile
독자보다 필자를 위해 포스팅합니다

0개의 댓글