spring boot + batch, servlet web server를 호출할때?

Dae-Hwa Jeong·2024년 5월 30일
0

batch 혹은 web server 호출 이외에도 독립적인 스프링 부트 애플리케이션을 실행하고 싶은데, 웹서버를 찾을 경우

의존성에 아래 사항이 포함되어 있는지 확인 후 제거

    private static final String[] SERVLET_INDICATOR_CLASSES = new String[]{"jakarta.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"};
    private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
    private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
    private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";

우회하려면 아래와 같이 webApplicationType을 강제로 넣어준다(SpringApplication 생성자 호출 이후 시점).

SpringApplication.exit(runApplication<AdPaymentBatchApplication>(*args){
    // setWebApplicationType(WebApplicationType.NONE)
    webApplicationType = org.springframework.boot.WebApplicationType.NONE
}

삽질...

Check your application's dependencies for a supported servlet web server. Check the configured web application type. org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.boot.web.context.MissingWebServerFactoryBeanException: No qualifying bean of type 'org.springframework.boot.web.servlet.server.ServletWebServerFactory' available: Unable to start AnnotationConfigServletWebServerApplicationContext due to missing ServletWebServerFactory bean

Trace 추적하여
SpringApplication.run 확인

try {
    ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
    this.configureIgnoreBeanInfo(environment);
    Banner printedBanner = this.printBanner(environment);
    context = this.createApplicationContext();
    context.setApplicationStartup(this.applicationStartup);
    this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
    // 여기서 ConfigurableApplicationContext 가 ServletWebServerApplicationContext 로 세팅 돼있음
    this.refreshContext(context);
    this.afterRefresh(context, applicationArguments);
    Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
    if (this.logStartupInfo) {
        (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
    }

    listeners.started(context, timeTakenToStartup);
    this.callRunners(context, applicationArguments);
}

batch job 등록: AbstractApplicationContext.refreshfinishBeanFactoryInitialization(beanFactory)

실제 Job 실행은 JobLauncherApplicationRunner가 callRunners 단계예서 실행된다.

그럼 확인해야할 것

  • context 올바르게 불러오는지
    - WebApplicationType.NONE 이어야 한다. 그래야 기본 컨텍스트를 가져온다(현재 문제는 서블릿 컨텍스트를 가져오는 것이기 때문에...)
  • runner 잘 등록됐는지

우선 원인은 javax.servlet:javax.servlet-api 가 의존성에 있었던 것...

의존성 제거해주거나 우회하거나 하면 되긴 한다

허나... 웹서버가 아닌 애플리케이션에서 참조하는 모듈에서 서블릿에 의존적인 코드를 작성한게 문제의 시발점이 아니었나 싶다.

비동기 호출시 trace 추적 우회를 하고 싶었는데, 
https://jsonobject.tistory.com/468 이런 식으로 시도해본 사람도 있고
Spring Cloud Sleuth를 사용하는게 목적에 더 적합했을 수도 있겠다

더 근본적으론 revert 먼저 하고 작업하지 않았던 점... 부끄럽지만 반성하자

profile
대화로그

0개의 댓글