티스토리 뷰

백기선 - 스프링 부트 개념과 활용

1. 의존성 관리 이해

  • https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using-boot-dependency-management

  • spring-boot-stater-* 의 부모인 spring-boot-stater-parent, 그리고 다시 그 parent의 부모인 spring-boot-dependencies 에 정의되어 있는 pom.xml의 dependencyManegement 영역 안에 해당 릴리즈 버전에서 관리하는 의존성들이 정의 되어 있다.

    • 그렇기 때문에 우리는 각 스타터의 버전을 명시하지 않아도 되고, parent가 관리하는 버전을 사용하게 된다.

  • gradle을 사용한다면 intellij의 gradle 탭에서 참조하고 있는 각 의존성들의 버전들과 하위 의존성들의 상세 버전까지 확인 할 수 있다.

  • 스프링 부트의 dependencies에서 관리하는 의존성의 경우 버전 명시를 하지 않고 stater 위주로 추가해서 사용하면 된다. 별도의 버전 호환을 체크 하지 않고 사용할 수 있다. 하지만, 특별히 버전을 명시해서 사용해야 하는 경우는 명시해서 사용하면 설정 값이 해당 버전으로 오버라이딩 되기 때문에 그 버전을 사용 할 수 있다.


2. 의존성 관리 응용

버전 관리 해주는 의존성 추가

  • 사용하고 싶은 dependency stater 등록

dependencies {
...
implementation('org.springframework.boot:spring-boot-starter-data-jpa')
...    
}
  • 스타터만 추가했을뿐인데, 해당 스프링 부트 릴리즈 버전에서 관리되고 있는 의존성의 하위 의존성들까지 추가가 된다.

버전 관리 안해주는 의존성 추가

  • 별도로 추가해야 하는 의존성들은 https://mvnrepository.com/ 를 통해서 검색해서 직접 추가하면 된다. 스타터의 parent에서 버전관리가 되지 않으므로 직접 버전까지 명시해줘야 한다.

기존 의존성 버전 변경하기

  • 추가적으로 부트에서 관리하고 있는 의존성의 버전을 개발자가 직접 수정해서 사용할 수 있다.

implementation('org.springframework.boot:spring-boot-starter-data-jpa:2.0.3.RELEASE')

3. 자동 설정 이해

  • @SpringBootApplication 이 선언되어 있는 메인 클래스에서 저 애노테이션을 따라 들어가보면,

  • @SpringBootConfiguration, @EnableAutoConfiguration, @ComponentScan 등이 선언되어 있다.

  • 애플리케이션에서 빈은 사실 두 단계로 나눠서 읽힌다.

    • 1단계 : @ComponentScan

    • 2단계 : @EnableAutoConfiguration

  • @ComponentScan 에서는

    • @Component

    • @Configuration, @Repository, @Service, @Controller, @RestController

    • 위의 애노테이션

  • @EnableAutoConfiguration 에서는

    • spring.factories

      • org.springframework.boot.autoconfigure.EnableAutoConfiguration

    • @Configuration

    • @ConditionalOnXxxYyyZzz


4. 자동 설정 만들기 1부: Starter와 AutoConfigure

  • Xxx-Spring-Boot-Autoconfigure 모듈: 자동 설정

  • Xxx-Spring-Boot-Starter 모듈 : 필요한 의존성 정의

  • 그냥 하나로 만들고 싶을 때는?

    • Xxx-Spring-Boot-Starter

  • 본인이 만든 의존성에 의해 만들어지는 빈이 @ComponentScan에 의해서 먼저 만들어지고,

  • 2번째 단계의 @EnableAutoConfiguration에 의해 @Configuration으로 설정되어있는 빈이 이것을 덮어 쓰는 경우도 생긴다.


5. 자동 설정 만들기 2부: @ConfigurationProperties

  • 정리해서 설명하자면, 본인이 애플리케이션에서 직접 @Bean 으로 정의한 holoman 이라는 빈이 AutoConfigure로 인해 만들어진 @Configuration으로 선언된 빈으로 덮어쓰여지는 문제가 생긴다. @SpringBootApplication이 1단계, 2단계로 나눠서 빈을 스캔하기 때문이다.

    • 이 경우에는 @AutoConfigure로 선언한 @Bean에 @ConditionalOnMissingBean 애노테이션을 추가해주면, 해당 타입 의 빈이 비어있을 경우에만 생성한다.

    • 결과적으로 1단계로 @ComponentScan이 이루어질때 빈이 만들어졌으면, 2단계 @EnableAutoConfiguration 에서는 만들어지지 않는다.

    • 따라서, 본인이 애플리케이션에 직접 생성한 @Bean의 우선순위가 높아지게 된다.

  • 추가적으로 application.yaml에 설정한 값을 @ConfigurationProperties를 통해서 빈에 주입할 수 있다.


6. 내장 웹 서버 이해

  • 부트는 서버가 아니다.

    • 톰캣 객체 생성

    • 포트 설정

    • 톰캣에 컨텍스트 추가

    • 서블릿 만들기

    • 톰캣에 서블릿 추가

    • 컨텍스트에 서블릿 맵핑

    • 톰캣 실행 및 대기

  • 이 모든 과정을 보다 상세히 또 유연하게 설정하고 실행해주는게 바로 스프링 부트의 자동 설정

    • ServletWebServerFactoryAutoConfiguration(서블릿 웹 서버 생성)

      • TomcatServletWebServerFactoryCustomizer(서버 커스터마이징)

    • DispatcherServletAutoConfiguration

      • 서블릿 만들고 등록

내장 웹 서버 응용 1부: 컨테이너와 포트

  • spring-boot-starter-web이 spring-boot-starter-tomcat을 가져온다.

  • 만약 tomcat이 아닌, 다른 tomcat이 아닌 jetty를 내장 웹서버로 사용하고 싶다면 아래와 같이 gradle 설정 파일을 작성해주면 된다.

...

configurations {
   compile.exclude module: 'spring-boot-starter-tomcat'
}


dependencies {
  ...
   implementation('org.springframework.boot:spring-boot-starter-web')
   implementation('org.springframework.boot:spring-boot-starter-jetty')
  ...
}
  • 부트를 웹 애플리케이션으로 띄우지 않으려면, 프로퍼티 설정을 통해서 일반 애플리케이션으로 사용할 수 있다. 서버의 포트도 간단하게 설정할 수 있다.

    • application.yml

    spring:
    main:
      web-application-type: none
       
    server:
    port: 9090
  • 서버 포트 정보를 0으로 할당하면, 사용 가능한 포트를 랜덤으로 선택한다.

server:
port: 0
  • 위와 같이 할당된 포트를 애플리케이션 코드에서 사용하는 best way를 spring boot 도큐먼트에서 설명하고 있다.

package io.namjune.springbootconceptandutilization;

import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class PortListener implements ApplicationListener<ServletWebServerInitializedEvent> {

   @Override
   public void onApplicationEvent(
       ServletWebServerInitializedEvent servletWebServerInitializedEvent) {
       ServletWebServerApplicationContext applicationContext =
           servletWebServerInitializedEvent.getApplicationContext();
       System.out.println(applicationContext.getWebServer().getPort());
  }
}

내장 웹 서버 응용 2부: HTTPS와 HTTP2

  • Spring Boot SSL key generate

    • 명령어 수행한 위치에 키스토어가 생성된다.

$ keytool -genkey -alias tomcat -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 4000
  • application.yml

server:
ssl:
  key-store: keystore.p12
  key-store-type: PKCS12
  key-store-password: 123456
  key-alias: tomcat
  • 이렇게 SSL 키를 등록하고 스프링부트 애플리케이션을 실행하면, localhost:8080으로 접근이 불가하다. 앞으로 애플리케이션으로의 모든 접근은 https로 해야한다.

  • 추가적으로 http 접근도 가능하게 설정하려면 아래와 같이 애플리케이션 코드에 http 요청을 받기 위한 커넥터를 추가해주면 된다. 대신 application.yml에서 https의 포트를 변경해준다.

...
 @Bean
   public ServletWebServerFactory serverFactory() {
       TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
       tomcat.addAdditionalTomcatConnectors(createStandardConnector());
       return tomcat;
  }

   private Connector createStandardConnector() {
       Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
       connector.setPort(8080);
       return connector;
  }
...
  • 로그 확인

...
2018-11-13 11:23:41.187 INFO 12432 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8443 (https) 8080 (http) with context path ''
...
  • HTTP2 설정은 SSL이 기본적으로 적용되어있는 상태에서 http2.enabled를 true로 할당해주면 된다.

    • 추가적으로 해줘야하는 작업은 각 웹서버마다 다르다(undertow는 https 설정이 되어있으면 추가적인 설정 없이 http2 enable만 true로 할당하면되고, tomcat은 9.X버전과 JDK9 이상을 쓰면 추가적인 설정없이 http2를 적용할 수 있다.)

server:
http2:
  enabled: true







댓글