You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
그리고 어디선가 내장 톰캣에 디스패처 서블릿을 등록하고, 스프링 컨테이너와 연결해서 동작할 수 있게 한다.
어디서 많이 본 것 같지 않은가?
스프링 부트도 우리가 앞서 내장 톰캣에서 진행했던 것과 동일한 방식으로 스프링 컨테이너를 만들고, 내장 톰캣을 생성하고 그 둘을 연결하는 과정을 진행한다.
지금까지 스프링 부트가 어떻게 톰캣 서버를 내장해서 실행하는지 스프링 부트의 비밀 하나를 풀어보았다. 다음에는 스프링 부트의 빌드와 배포 그리고 스프링 부트가 제공하는 jar 의 비밀을 알아보자.
스프링 부트와 웹 서버 - 빌드와 배포
jar 파일 실행
jar 파일이 있는 폴더로 이동한 후에 다음 명령어로 jar 파일을 실행해보자.
java -jar boot-0.0.1-SNAPSHOT.jar
실행 결과
... % java -jar boot-0.0.1-SNAPSHOT.jar
o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080
(http) with context path ''
hello.boot.BootApplication : Started BootApplication in 0.961
seconds
스프링 부트 애플리케이션이 실행되고, 내장 톰캣이 8080 포트로 실행된 것을 확인할 수 있다.
스프링 부트 jar 분석
boot-0.0.1-SNAPSHOT.jar 파일 크기를 보면 대략 18M 정도 된다. 참고로 버전에 따라서 용량은 변할 수 있다.
아마도 앞서 배운 Fat Jar와 비슷한 방식으로 만들어져 있지 않을까? 생각될 것이다.
비밀을 확인하기 위해 jar 파일의 압축을 풀어보자.
- JAR를 푼 결과를 보면 Fat Jar가 아니라 처음보는 새로운 구조로 만들어져 있다. 심지어 jar 내부에 jar를 담아서 인식하는 것이 불가능한데, jar가 포함되어 있고, 인식까지 되었다. 지금부터 스프링 부트가 제공하는 jar에 대해서 알아보자.
참고
빌드 결과를 보면 boot-0.0.1-SNAPSHOT-plain.jar 파일도 보이는데, 이것은 우리가 개발한 코드만 순수한 jar로 빌드한 것이다. 무시하면 된다.
스프링 부트 실행 가능 Jar
Fat Jar는 하나의 Jar 파일에 라이브러리의 클래스와 리소스를 모두 포함했다. 그래서 실행에 필요한 모든 내용을 하나의 JAR로 만들어서 배포하는 것이 가능했다. 하지만 Fat Jar는 다음과 같은 문제를 가지고 있다.
Fat Jar의 단점
어떤 라이브러리가 포함되어 있는지 확인하기 어렵다.
모두 class 로 풀려있으니 어떤 라이브러리가 사용되고 있는지 추적하기 어렵다.
파일명 중복을 해결할 수 없다.
클래스나 리소스 명이 같은 경우 하나를 포기해야 한다. 이것은 심각한 문제를 발생한다. 예를 들어서 서블릿 컨테이너 초기화에서 학습한 부분을 떠올려 보자.
META-INF/services/jakarta.servlet.ServletContainerInitializer 이 파일이 여러 라이브러리( jar )에 있을 수 있다.
A 라이브러리와 B 라이브러리 둘다 해당 파일을 사용해서 서블릿 컨테이너 초기화를 시도한다. 둘다 해당 파일을 jar 안에 포함한다.
Fat Jar 를 만들면 파일명이 같으므로 A , B 둘중 하나의 파일만 선택된다. 결과적으로 나머지는 정상 동작하지 않는다.
실행 가능 Jar
스프링 부트는 이런 문제를 해결하기 위해 jar 내부에 jar를 포함할 수 있는 특별한 구조의 jar를 만들고 동시에 만든 jar를 내부 jar를 포함해서 실행할 수 있게 했다. 이것을 실행 가능 Jar(Executable Jar)라 한다. 이 실행 가능 Jar를 사용하면 다음 문제들을 깔끔하게 해결할 수 있다.
문제: 어떤 라이브러리가 포함되어 있는지 확인하기 어렵다.
해결: jar 내부에 jar를 포함하기 때문에 어떤 라이브러리가 포함되어 있는지 쉽게 확인할 수 있다.
문제: 파일명 중복을 해결할 수 없다.
해결: jar 내부에 jar를 포함하기 때문에 a.jar, b.jar 내부에 같은 경로의 파일이 있어도 둘 다 인식할 수 있다.
참고로 실행 가능 Jar는 자바 표준은 아니고, 스프링 부트에서 새롭게 정의한 것이다.
실행 가능 Jar 내부 구조
Jar 실행 정보
java -jar xxx.jar 를 실행하게 되면 우선 META-INF/MANIFEST.MF 파일을 찾는다. 그리고 여기에 있는 Main-Class 를 읽어서 main() 메서드를 실행하게 된다. 스프링 부트가 만든 MANIFEST.MF 를 확인해보자.
우리가 기대한 main() 이 있는 hello.boot.BootApplication 이 아니라 JarLauncher 라는 전혀 다른 클래스를 실행하고 있다.
JarLauncher 는 스프링 부트가 빌드시에 넣어준다. org/springframework/boot/loader/JarLauncher 에 실제로 포함되어 있다.
스프링 부트는 jar 내부에 jar를 읽어들이는 기능이 필요하다. 또 특별한 구조에 맞게 클래스 정보도 읽어들여야 한다. 바로 JarLauncher 가 이런 일을 처리해준다. 이런 작업을 먼저 처리한 다음 StartClass: 에 지정된 main() 을 호출한다.
Start-Class : 우리가 기대한 main() 이 있는 hello.boot.BootApplication 가 적혀있다.
기타: 스프링 부트가 내부에서 사용하는 정보들이다.
Spring-Boot-Version : 스프링 부트 버전
Spring-Boot-Classes : 개발한 클래스 경로
Spring-Boot-Lib : 라이브러리 경로
Spring-Boot-Classpath-Index : 외부 라이브러리 모음
Spring-Boot-Layers-Index : 스프링 부트 구조 정보
참고: Main-Class 를 제외한 나머지는 자바 표준이 아니다. 스프링 부트가 임의로 사용하는 정보이다.
스프링 부트 로더
org/springframework/boot/loader 하위에 있는 클래스들이다.
JarLauncher 를 JarLauncher 를 포함한 스프링 부트가 제공하는 실행 가능 Jar를 실제로 구동시키는 클래스들이 포함되어 있다. 스프링 부트는 빌드시에 이 클래스들을 포함해서 만들어준다.포함한 스프링 부트가 제공하는 실행 가능 Jar를 실제로 구동시키는 클래스들이 포함되어 있다. 스프링 부트는 빌드시에 이 클래스들을 포함해서 만들어준다.
BOOT-INF
classes : 우리가 개발한 class 파일과 리소스 파일
lib : 외부 라이브러리
classpath.idx : 외부 라이브러리 모음
layers.idx : 스프링 부트 구조 정보
WAR구조는 WEB-INF 라는 내부 폴더에 사용자 클래스와 라이브러리를 포함하고 있는데, 실행 가능 Jar도 그 구조를 본따서 만들었다. 이름도 유사하게 BOOT-INF 이다.
JarLauncher 를 통해서 여기에 있는 classes 와 lib 에 있는 jar 파일들을 읽어들인다.
실행 과정 정리
java -jar xxx.jar
MANIFEST.MF 인식
JarLauncher.main() 실행
BOOT-INF/classes/ 인식
BOOT-INF/lib/ 인식
BootApplication.main() 실행
참고
실행 가능 Jar가 아니라, IDE에서 직접 실행할 때는 BootApplication.main() 을 바로 실행한다. IDE가 필요한 라이브러리를 모두 인식할 수 있게 도와주기 때문에 JarLauncher 가 필요하지 않다.
스프링 부트 스타터와 라이브러리 관리
라이브러리 관리의 어려움
프로젝트를 처음 시작하면 어떤 라이브러리들을 사용할지 고민하고 선택해야 한다. 예를 들어서 스프링 WEB, 내장 톰캣, JSON 처리기, 로거 등등 수 많은 라이브러리를 선택해야 한다. 여기에 추가로 각 라이브러리의 버전까지 고민해야한다. 더 심각한 문제는 각 라이브러리들끼리 호환이 잘 되는 버전도 있지만 잘 안되는 버전들도 있다. 과거에는 이런 문제들 때문에 처음 프로젝트를 세팅하는데 상당히 많은 시간을 소비했다.
스프링 부트는 개발자가 라이브러리들을 편리하게 사용할 수 있는 다양한 기능들을 제공한다.
외부 라이브러리 버전 관리
스프링 부트 스타터 제공
라이브러리 직접 관리
스프링 부트가 제공하는 편리한 라이브러리 관리 기능을 사용해보기 전에, 잠깐 과거로 돌아가서 직접 라이브러리를 하나하나 고르고 설정하는 방법을 알아보자.
다음 예는 스프링 웹과 내장 톰캣을 사용하는 웹 애플리케이션이다.
build.gradle 확인
plugins {
id'org.springframework.boot'version'3.0.2'//id 'io.spring.dependency-management' version '1.1.0'id'java'
}
group = 'hello'version = '0.0.1-SNAPSHOT'sourceCompatibility = '17'//스프링 부트 외부 라이브러리 버전 변경//ext['tomcat.version']='10.1.4'configurations {
compileOnly {
extendsFromannotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
//1. 라이브러리 직접 지정//스프링 웹 MVCimplementation'org.springframework:spring-webmvc:6.0.4'//내장 톰캣implementation'org.apache.tomcat.embed:tomcat-embed-core:10.1.5'//JSON 처리implementation'com.fasterxml.jackson.core:jackson-databind:2.14.1'//스프링 부트 관련implementation'org.springframework.boot:spring-boot:3.0.2'implementation'org.springframework.boot:spring-boot-autoconfigure:3.0.2'//LOG 관련implementation'ch.qos.logback:logback-classic:1.4.5'implementation'org.apache.logging.log4j:log4j-to-slf4j:2.19.0'implementation'org.slf4j:jul-to-slf4j:2.0.6'//YML 관련implementation'org.yaml:snakeyaml:1.33'/* //2. 스프링 부트 라이브러리 버전 관리 //스프링 웹, MVC implementation 'org.springframework:spring-webmvc' //내장 톰캣 implementation 'org.apache.tomcat.embed:tomcat-embed-core' //JSON 처리 implementation 'com.fasterxml.jackson.core:jackson-databind' //스프링 부트 관련 implementation 'org.springframework.boot:spring-boot' implementation 'org.springframework.boot:spring-boot-autoconfigure' //LOG 관련 implementation 'ch.qos.logback:logback-classic' implementation 'org.apache.logging.log4j:log4j-to-slf4j' implementation 'org.slf4j:jul-to-slf4j' //YML 관련 implementation 'org.yaml:snakeyaml'*//* //3. 스프링 부트 스타터 implementation 'org.springframework.boot:spring-boot-starter-web'*/
}
tasks.named('test') {
useJUnitPlatform()
}
스프링 웹 애플리케이션을 실행하려면 생각보다 수 많은 라이브러리가 필요하다.
스프링 웹 MVC, 내장 톰캣, JSON 처리, 스프링 부트 관련, LOG, YML 등등 다양한 라이브러리가 사용된다.
참고
io.spring.dependency-management 플러그인은 일부로 적용하지 않았다. 자세한 내용은 뒤에서 설명한다.
참고 - 스프링 부트가 관리하지 않는 라이브러리
스프링 부트가 관리하지 않는 외부 라이브러리도 있다. 특히 아직 잘 알려지지 않거나 대중적이지 않은 경우
가 그러한데, 이때는 다음과 같이 라이브러리의 버전을 직접 적어주어야 한다.
implementation 'org.yaml:snakeyaml:1.30'
정리
스프링 부트가 제공하는 버전 관리는 스프링 자신을 포함해서 수 많은 외부 라이브러리의 버전을 최적화 해서 관리해준다. 이제 개발자는 스프링 부트 자체의 버전만 지정하면 된다. 그리고 스프링 부트가 해당 스프링 부트 버전에 맞는 각 라이브러리의 호환성을 테스트 했기 때문에 안전하게 사용할 수 있다.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
스프링 부트와 웹 서버 - 프로젝트 생성
HelloController
내장 톰캣 의존관계 확인
spring-boot-starter-web를 사용하면 내부에서 내장 톰캣을 사용한다.라이브러리 버전
스프링 부트와 웹 서버 - 실행 과정
main()메서드에서SpringAppliocation.run()을 호출해주면 된다.@SpringBootApplication애노테이션이 있는 현재 클래스를 지정해주면 된다.@SpringBootApplication애노테이션이 있는데, 이 애노테이션 안에는 컴포넌트 스캔을 포함한 여러 기능이 설정되어 있다. 기본 설정은 현재 패키지와 그 하위 패키지 모두를 컴포넌트 스캔한다.이 단순해 보이는 코드 한줄 안에서는 수 많은 일들이 발생하지만 핵심은 2가지다.
스프링 부트 내부에서 스프링 컨테이너를 생성하는 코드
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContextFactorynew AnnotationConfigServletWebServerApplicationContext()이 부분이 바로 스프링 부트가 생성하는 스프링 컨테이너이다.스프링 부트 내부에서 내장 톰캣을 생성하는 코드
org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory그리고 어디선가 내장 톰캣에 디스패처 서블릿을 등록하고, 스프링 컨테이너와 연결해서 동작할 수 있게 한다.
어디서 많이 본 것 같지 않은가?
지금까지 스프링 부트가 어떻게 톰캣 서버를 내장해서 실행하는지 스프링 부트의 비밀 하나를 풀어보았다. 다음에는 스프링 부트의 빌드와 배포 그리고 스프링 부트가 제공하는 jar 의 비밀을 알아보자.
스프링 부트와 웹 서버 - 빌드와 배포
jar 파일 실행
jar파일을 실행해보자.java -jar boot-0.0.1-SNAPSHOT.jar실행 결과
스프링 부트 jar 분석
아마도 앞서 배운 Fat Jar와 비슷한 방식으로 만들어져 있지 않을까? 생각될 것이다.
비밀을 확인하기 위해 jar 파일의 압축을 풀어보자.
참고
스프링 부트 실행 가능 Jar
Fat Jar의 단점
실행 가능 Jar
스프링 부트는 이런 문제를 해결하기 위해 jar 내부에 jar를 포함할 수 있는 특별한 구조의 jar를 만들고 동시에 만든 jar를 내부 jar를 포함해서 실행할 수 있게 했다. 이것을 실행 가능 Jar(Executable Jar)라 한다. 이 실행 가능 Jar를 사용하면 다음 문제들을 깔끔하게 해결할 수 있다.
문제: 어떤 라이브러리가 포함되어 있는지 확인하기 어렵다.
문제: 파일명 중복을 해결할 수 없다.
참고로 실행 가능 Jar는 자바 표준은 아니고, 스프링 부트에서 새롭게 정의한 것이다.
실행 가능 Jar 내부 구조
Jar 실행 정보
META-INF/MANIFEST.MF스프링 부트 로더
BOOT-INF
실행 과정 정리
참고
스프링 부트 스타터와 라이브러리 관리
라이브러리 관리의 어려움
스프링 부트는 개발자가 라이브러리들을 편리하게 사용할 수 있는 다양한 기능들을 제공한다.
라이브러리 직접 관리
build.gradle 확인
참고
동작 확인
스프링 부트 라이브러리 버전 관리
dependency-management 버전 관리
bom 정보를 참고한다.
관계로 보이지는 않는다.
버전 정보 bom
참고 - BOM(Bill of materials)
자재 명세서(Bill of materials)란 제품구성하는 모든 부품들에 대한 목록이다.
부품이 복잡한 요소들로 구성된 조립품인 경우는 계층적인 구조로 작성될 수 있다. - 위키백과
참고 - 스프링 부트가 관리하는 외부 라이브러리 버전을 확인하는 방법
https://docs.spring.io/spring-oot/docs/current/reference/html/dependencyversions.html#appendix.dependency-versions.coordinates
참고 - 스프링 부트가 관리하지 않는 라이브러리
스프링 부트가 관리하지 않는 외부 라이브러리도 있다. 특히 아직 잘 알려지지 않거나 대중적이지 않은 경우
가 그러한데, 이때는 다음과 같이 라이브러리의 버전을 직접 적어주어야 한다.
implementation 'org.yaml:snakeyaml:1.30'
정리
스프링 부트가 제공하는 버전 관리는 스프링 자신을 포함해서 수 많은 외부 라이브러리의 버전을 최적화 해서 관리해준다. 이제 개발자는 스프링 부트 자체의 버전만 지정하면 된다. 그리고 스프링 부트가 해당 스프링 부트 버전에 맞는 각 라이브러리의 호환성을 테스트 했기 때문에 안전하게 사용할 수 있다.
Beta Was this translation helpful? Give feedback.
All reactions