2. 스프링 부트 원리
About 2 min
2. 스프링 부트 원리 관련
namjunemy/TIL - [스프링 부트 개념과 활용] 2. 스프링 부트 원리
[스프링 부트 개념과 활용] 2. 스프링 부트 원리
1. 의존성 관리 이해
Spring Boot Reference Documentation
6.1.1. Dependency Management
spring-boot-stater-*
의 부모인spring-boot-stater-parent
, 그리고 다시 그 parent의 부모인spring-boot-dependencies
에 정의되어 있는pom.xml
의dependencyManegement
영역 안에 해당 릴리즈 버전에서 관리하는 의존성들이 정의 되어 있다.- 그렇기 때문에 우리는 각 스타터의 버전을 명시하지 않아도 되고, parent가 관리하는 버전을 사용하게 된다.
- gradle을 사용한다면 intellij의
gradle
탭에서 참조하고 있는 각 의존성들의 버전들과 하위 의존성들의 상세 버전까지 확인 할 수 있다.
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
- 1단계:
@ComponentScan
에서는@Component
@Configuration
,@Repository
,@Service
,@Controller
,@RestController
- 위의 애노테이션
@EnableAutoConfiguration
에서는- spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration
@Configuration
@ConditionalOnXxxYyyZzz
- spring.factories
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
를 통해서 빈에 주입할 수 있다.- 해당 커밋 내용 참조
- https://github.com/namjunemy/spring-boot-concept-and-utilization/commit/53b92ad92935a0568bb28c2a7d95298c995ebfdb
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.yaml
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.yaml
server:
ssl:
key-store: keystore.p12
key-store-type: PKCS12
key-store-password: 123456
key-alias: tomcat
이렇게 SSL 키를 등록하고 스프링부트 애플리케이션을 실행하면,
localhost:8080
으로 접근이 불가하다. 앞으로 애플리케이션으로의 모든 접근은 https로 해야한다.추가적으로 http 접근도 가능하게 설정하려면 아래와 같이 애플리케이션 코드에 http 요청을 받기 위한 커넥터를 추가해주면 된다. 대신
application.yaml
에서 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를 적용할 수 있다.)
- 추가적으로 해줘야하는 작업은 각 웹서버마다 다르다(undertow는 https 설정이 되어있으면 추가적인 설정 없이 http2 enable만
server:
http2:
enabled: true