[토비의 스프링부트] 스프링 부트 컨테이너리스 특성 이해하기

박상준·2024년 6월 14일
0
  • 스프링 부트에서 컨테이너리스(Containerless) 가 어떻게 만들어졌고 어떻게 동작하나?

컨테이너리스의 개념

  • 서블릿 컨테이너와 관련된 복잡하고 번거로운 작업들을 개발자가 신경 쓰지 않고 애플리케이션 개발에만 집중할 수 있도록 하는 것이 목표이다.
  • 서블릿 컨테이너 설치, 웹.xml 설정, 배포 등의 작업을 자동으로 처리해 준다.
  • 간단한 메인 메서드 실행만으로 스프링 애플리케이션을 동작시킬 수 있다.

스프링부트의 메인 메서드

package com.company.tobispringboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class TobiSpringBootApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(TobiSpringBootApplication.class, args);
    }
    
}
  • 부트에서는 단순히 main 메서드에서 어떤식으로 스프링 컨테이너를 올리는 작업을 수행하는 걸까?
  • 어노테이션과 관련 실행 메서드를 지우고 수행해보자
package com.company.tobispringboot;

public class TobiSpringBootApplication {
    
    public static void main(String[] args) {
        System.out.println("Hello Containerless Standalone Spring Boot!");
    }
}
  • 단순히 콘솔에
Hello Containerless Standalone Spring Boot!

가 찍히게 된다.

  • 해당 상태에서 Hello Controller 가 이전처럼 어떤식으로 잘 동작하게 만드는 지 그 방법을 이제부터 알아보자.

Java 로 Tomcat Servlet Container 구현해보기

  • 목표

    • 서블릿 컨테이너 설치와 관련된 복잡한 작업 없이 애플리케이션 코드 빈 개발에 집중해보자
    • Tomcat 서블릿 컨테이너를 코드로 간편하게 띄워보자.
  • 코드

    package com.company.tobispringboot;
    
    import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
    import org.springframework.boot.web.server.WebServer;
    import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
    
    public class TobiSpringBootApplication {
        
        public static void main(String[] args) {
            ServletWebServerFactory factory = new TomcatServletWebServerFactory();
            
            WebServer webServer = factory.getWebServer();
            webServer.start();
        }
    }
    • Tomcat 을 통해 start 를 해도 되지만,, Tomcat 을 구동시키기 위한 별도의 설정이 필요하기에,

      자바에서 구동을 쉽게 하도록 ServletWebServerFactory 로 이미 추상화를 시켜놓음

      구현체는 Jetty Tomcat Undertow 가 존재한다

      Factory 의 getWebServer 를 통해 현재 내가 구동할 Servlet 서버에 대한 정보를 불러온다.

      이후 start() 하면

      @Override
      	public void start() throws WebServerException {
      		synchronized (this.monitor) {
      			if (this.started) {
      				return;
      			}
      			try {
      				addPreviouslyRemovedConnectors();
      				Connector connector = this.tomcat.getConnector();
      				if (connector != null && this.autoStart) {
      					performDeferredLoadOnStartup();
      				}
      				checkThatConnectorsHaveStarted();
      				this.started = true;
      				logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '"
      						+ getContextPath() + "'");
      			}
      			catch (ConnectorStartFailedException ex) {
      				stopSilently();
      				throw ex;
      			}
      			catch (Exception ex) {
      				PortInUseException.throwIfPortBindingException(ex, () -> this.tomcat.getConnector().getPort());
      				throw new WebServerException("Unable to start embedded Tomcat server", ex);
      			}
      			finally {
      				Context context = findContext();
      				ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
      			}
      		}
      	}
      • 스레드 경합 방지를 위해 sync 처리하고, 시작여부에 따라 구동을 결정한다.
profile
이전 블로그 : https://oth3410.tistory.com/

0개의 댓글