스프링부트

Spring boot embedded server 의 default 포트 변경

알쓸개잡 2023. 9. 16.

기본적으로 Spring Boot 애플리케이션은 임베디드 톰캣 서버의 포트 8080으로 동작한다. Spring Boot의 기본 임베디드 서버 포트를 다른 포트로 변경할 수 있는 몇 가지 방법에 대해서 기록한다.

포트 충돌 방지를 위해서 임의의 사용 가능한 포트를 사용하려면 server.port=0으로 설정한다.

 

방법 1) properties(. yml) 파일에서 기본 포트 변경

Spring Boot에서 기본적으로 참조하는 application.yml(.properties) 파일 설정으로 기본 포트를 변경할 수 있다.

# application.properties
server.port=9090

# application.yml
server:
  port:9090

 

방법 2) 코드상에서 기본 포트 변경

코드상에서는 기본 포트뿐만 아니라 다른 여러 설정들도 변경할 수 있다.

WebServerFactoryCustomizer 인터페이스는 임베디드 서버의 설정을 커스터마이징 하는 데 사용된다.

WebServerFactoryCustomizer 인터페이스에 대한 호출은 일반적으로 ApplicationContext 라이프 사이클의 초기에 호출되는 BeanPostProcessor를 구현한 WebServerFactoryCustomizerBeanPostProcessor 내에서 이루어진다.

WebServerFactoryCustomizer를 구현하는 모든 빈은 컨테이너 자체가 시작되기 전에 컨테이너 팩토리와 함께 콜백을 받아서 포트, 주소, 오류 페이지 등을 설정할 수 있다.

 

WebServerFactoryCustomizer interface

@Component
public class WebServerConfigCustomizer implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> {
	@Override
	public void customize(ConfigurableWebServerFactory factory) {
		factory.setPort(9090);
		factory.setShutdown(Shutdown.GRACEFUL);
	}
}


---------------------------------------------------------------------
혹은

/**
    ConfigurableWebServerFactory의 구현체 타입을 특정하여 더 많은 설정을 할 수도 있을 것 같다.
*/
@Component
public class WebServerConfigCustomizer implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> {
	@Override
	public void customize(ConfigurableWebServerFactory factory) {
		if (factory instanceof TomcatServletWebServerFactory tomcatServletWebServerFactory) {
			tomcatServletWebServerFactory.setPort(9090);
			tomcatServletWebServerFactory.setShutdown(Shutdown.GRACEFUL);
		} else if (factory instanceof UndertowServletWebServerFactory undertowServletWebServerFactory) {
			undertowServletWebServerFactory.setPort(9090);
			undertowServletWebServerFactory.setShutdown(Shutdown.GRACEFUL);
		}
        ...
	}
}

 

ConfigurableWebServerFactory는 인터페이스로써 아래의 구현체들이 주입될 수 있다.

Spring 에서 지원하는 내장 서블릿

디폴트로는 TomcatServletWebServerFactory 타입의 객체가 주입된다.

WebServerFactoryCustomizer<ConfigurableWebServerFactory> 인터페이스를 구현하는 WebServerConfigCustomizer의 customize(ConfigurableWebServerFactory factory) 메서드는 애플리케이션 구동 초기에 호출되는 WebServerFactoryCustomizerBeanPostProcessor의 postProcessBeforeInitialization 내에서 호출된다.

 

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    if (bean instanceof WebServerFactory webServerFactory) {
        postProcessBeforeInitialization(webServerFactory);
    }
    return bean;
}

...

@SuppressWarnings("unchecked")
private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
    LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory)
        .withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
        .invoke((customizer) -> customizer.customize(webServerFactory));
}

private Collection<WebServerFactoryCustomizer<?>> getCustomizers() {
    if (this.customizers == null) {
        // Look up does not include the parent context
        this.customizers = new ArrayList<>(getWebServerFactoryCustomizerBeans());
        this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE);
        this.customizers = Collections.unmodifiableList(this.customizers);
    }
    return this.customizers;
}

위 코드는 WebServerFactoryCustomizerBeanPostProcessor의 postProcessBeforeInitialization() 메서드의 코드이다.

WebServerFactoryCustomizer.class를 구현하는 모든 빈 클래스를 가져와서 cutomize(WebServerFactory) 를 호출한다.

여기서 직접 구현한 WebServerConfigCustomizer의 customize(WebServerFactory)도 함께 호출되어 기본 포트를 8080 -> 9090으로 변경하고 shutdown 정책을 IMMEDIATE -> GRACEFUL로 변경하게 되는 것이다.

 

디버깅을 통해 위에서 설명한 호출 흐름이 어떻게 되는지 살펴보자.

참고로 WebServerFactoryCustomizerBeanPostProcessor 클래스는 spring boot 3.1.3 버전 기준으로 org.springframework.boot:spring-boot:3.1.3 artifact의 spring-boot-3.1.3.jar의 org.springframework.boot.web.server 패키지 내에 정의되어 있다.

 

먼저 WebServerFactoryCustomizerBeanPostProcessor클래스에서 postProcessBeforeInitialization내 코드에 브레이크 포인트를 걸어서 추적을 시작해 본다. 

디버깅 실행 후 브레이크 포인트 지점을 확인해 보면 아래와 같다.

webServerFactory는 TomcatServletWebServerFactory타입이 주입

WebServerFactoryCustomizer.class를 구현한 빈들의 목록은 아래와 같다.

WebServerFactoryCustomizer.class를 구현한 빈 클래스 목록

직접 구현한 WebServerConfigCustomizer 빈 클래스도 포함되어 있는 것을 알 수 있다.

.invoke() 내에서 각 customizer 빈 클래스들의 customize() 메서드를 실행시키는데 직접 구현한 WebServerConfigCustomizer의 customize() 내부로 들어가 보면 상태는 아래와 같다.

WebServerConfigCustomizer의 customize 코드 진입 시점

customize() 메서드 파라미터로 전달된 factory는 WebServerFactoryCustomizerBeanPostProcessor의 postProcessBeforeInitialization(WebServerFactory webServerFactory)에 주입된 TomcatServletWebServerFactory와 동일 함을 알 수 있다.

factory.setPort(9090), factory.setShutdown(Shutdown.GRACEFUL) 이 호출되기 전에 factory에 셋팅된 port와 shutdown 상태를 보면 아래와 같다.

customize() 메서드 수행이 완료된 이후 factory의 속성 값을 살펴보면 아래와 같이 변경되었음을 알 수 있다.

애플리케이션 로그 상으로 기본 포트 설정과 shutdown 정책이 적용되었음을 알 수 있다.

...
o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9090 (http) with context path ''
...
o.s.b.w.e.tomcat.GracefulShutdown        : Graceful shutdown complete

 

방법 3) CLI에서 기본 포트 변경

실행 가능한 jar를 실행하는 경우 JVM 시스템 속성 지정을 통해서 변경할 수 있다.

$ java -jar -Dserver.port=9090 target/default-port-0.0.1-SNAPSHOT.jar

 

댓글

💲 추천 글