ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 3. 스프링 부트와 내장 톰캣
    Spring-Boot/스프링부트 - 핵심 원리와 활용 2023. 5. 15. 12:48

    1. WAR 배포 방식의 단점

    - 웹 애플리케이션을 개발하고 배포하려면 다음과 같은 과정을 거쳐야 한다.

        ㆍ톰캣과 같은 웹 애플리케이션 서버(WAS)를 별도로 설치해야 한다.

        ㆍ애플리케이션 코드를 WAR로 빌드해야 한다.

        ㆍ빌드한 WAR 파일을 WAS에 배포해야 한다.

    - 웹 애플리케이션을 구동하고 싶으면 웹 애플케이션 서버를 별도로 설치해야 하는 구조이다.

    - 과거에는 이렇게 웹 애플리케이션 서버와 웹 애플리케이션 빌드 파일(WAR)이 분리되어 있는 것이 당연한 구조 였다.

     

    * 단점 *

    - 톰캣 같은 WAS를 별도로 설치해야 한다.

    - 개발 환경 설정이 복잡하다.

        ㆍ단순한 자바라면 별도의 설정을 고민하지 않고, `main()` 메서드만 실행하면 된다.

        ㆍ웹 애플리케이션 WAS 실행하고 또 WAS와 연동하기 위한 복잡한 설정이 들어간다.

    - 배포 과정이 복잡하다. WAR를 만들고 이것을 또 WAS에 전달해서 배포해야 한다.

    - 톰캣의 버전을 변경하려면 톰캣을 다시 설치해야 한다.

     

    * 외장 서버 VS 내장 서버 *

    - 왼쪽 그림은 웹 애플리케이션 서버에 WAR 파일을 배포하는 방식, WAS를 실행해서 동작한다.

    - 오른쪽 그림은 애플리케이션 JAR 안에 다양한 라이브러리들과 WAS 라이브러리가 포함되는 방식, `main()` 메서드를 실행해서 동작한다.

     

    2. 내장 톰캣1 - 설정

    3. 내장 톰캣2 - 서블릿

    * 참고 *

    - 내장 톰캣을 개발자가 직접 다룰일은 거의 없다.

    - 스프링 부트에서 내장 톰캣 관련된 부분을 거의 대부분 자동화해서 제공하기 때문에 내장 톰캣을 깊이있게 학습하는 것은 권장하지 않는다. ( 백엔드 개발자는 이미 공부해야 할 것이 너무 많다.)

    - 내장 톰캣이 어떤 방식으로 동작하는지 그 원리를 대략 이해하는 정도면 충분하다.

     

    `main()` 메서드 실행 시 동작

        ㆍ내장 톰캣을 생성해서 `8080` 포트로 연결하도록 설정한다.

        ㆍ스프링 컨테이너를 만들고 필요한 빈을 등록한다.

        ㆍ스프링 MVC 디스패처 서블릿을 만들고 앞서 만든 스프링 컨테이너에 연결한다.

        ㆍ디스패처 서블릿을 내장 톰캣에 등록한다

        ㆍ내장 톰캣을 실행한다.

     

    4. 내장 톰캣3 - 스프링

    5. 내장 톰캣4 - 빌드와 배포1

    * jar 파일은 jar 파일을 포함할 수 없다. *

    - WAR와 다르게 JAR 파일은 내부에 라이브러리 역할을 하는 JAR 파일을 포함할 수 없다.

        ㆍ포함한다고 해도 인식이 안된다.

        ㆍ이것이 JAR 파일 스펙의 한계이다.

        ㆍ그렇다고 WAR를 사용할 수도 없다.

        ㆍWAR는 웹 애플리케이션 서버(WAS) 위에서만 실행할 수 있다.

    - 대안으로는 라이브러리 jar 파일을 모두 구해서 MANIFEST 파일에 해당 경로를 적어주면 인식이 되지만 매우 번거롭고, Jar 파일안에 Jar 파일을 포함할 수 없기 때문에 라이브러리 역할을 하는 jar 파일도 항상 함께 가지고 다녀야 한다.

        ㆍ이 방법은 권장하기 않기 때문에 따로 설명하지 않는다.

     

    6. 내장 톰캣 5 - 빌드와 배포2

    FatJar

    - 대안으로는 'fat jar' 또는 'uber jar' 라고 불리는 방법이다.

    - Jar 안에는 Jar를 포함할 수 없다. 하지만 클래스는 얼마든지 포함할 수 있다.

    - 라이브러리에 사용되는 `jar` 를 풀면 `class` 들이 나온다. 이 `class` 를 뽑아서 새로 만드는 `jar` 에 포함하는 것이다.

    - 이렇게 하면 수 많은 라이브러리에서 나오는 `class` 때문에 뚱뚱한(fat) `jar` 가 탄생한다. 그래서 `Fat Jar` 라고 부른다.

     

    *Fat Jar의 장점*

    - Fat Jar 덕분에 하나의 jar 파일에 필요한 라이브러리들을 내장할 수 있게 되었다.

    - 내장 톰캣 라이브러리를 jar 내부에 내장할 수 있게 되었다.

    - 덕분에 하나의 jar 파일로 배포부터, 웹 서버 설치 + 실행까지 모든 것을 단순화 할 수 있다.

     

    * WAR 단점과 해결 *

    - 톰캣 같은 WAS를 별도로 설치해야 한다.

        ㆍ해결 : WAS를 별도로 설치하지 않아도 된다. 톰캣 같은 WAS가 라이브러리로 jar 내부에 포함되어 있다.

    - 개발 환경 설정이 복잡하다.

        ㆍ단순한 자바라면 별도의 설정을 고민하지 않고, `main()` 메서드만 실행하면 된다.

        ㆍ웹 애플리케이션은 WAS를 연동하기 위한 복잡한 설정이 들어간다.

        ㆍ해결 : IDE에 복잡한 WAS 설정이 필요하지 않다. 단순히 `main()` 메서드만 실행하면 된다.

    - 배포 과정이 복잡하다. WAR를 만들고 이것을 또 WAS에 전달해서 배포해야 한다.

        ㆍ해결 : 배포 과정이 단순하다. JAR를 만들고 이것을 원하는 위치에서 실행만 하면 된다.

    - 톰캣의 버전을 업데이트 하려면 톰캣을 다시 설치해야 한다.

        ㆍ해결 : gradle에서 내장 톰캣 라이브러리 버전만 변경하고 빌드 후 실행하면 된다.

     

    * Fat Jar의 단점 *

    - 어떤 라이브러리가 포함되어 있는지 확인하기 어렵다.

        ㆍ모두 `class`로 풀려있으니 어떤 라이브러리가 사용되고 있는지 추적하기 어렵다

    - 파일명 중복을 해결할 수 없다.

        ㆍ클래스나 리소스 명이 같은 경우 하나를 포기해야 한다. 이것이 심각한 문제를 발생한다.

        ㆍ`META-INF/services/jakarta.servlet.ServletContainerInitializer` 이 파일이 여러 라이브러리(`jar`)에 있을 수 있다.

        ㆍ'A' 라이브러리와 `B` 라이브러리 둘다 해당 파일을 사용해서 서블릿 컨테이너 초기화를 시도한다.

             둘다 해당 파일을 `jar` 안에 포함한다.

        ㆍ`Fat Jar`를 만들면 파일명이 같으므로 `A`,`B` 라이브러리 둘다 가지고 있는 파일 중에 하나의 파일만 선택된다.

             결과적으로 나머지 하나는 포함되지 않으므로 정상 동작하지 않는다.

     

    7. 편리한 부트 클래스 만들기

    8. 스프링 부트와 웹 서버 - 프로젝트 생성 

    - 스프링 부트는 지금까지 고민한 문제를 깔끔하게 해결해준다.

        ㆍ내장 톰캣을 사용해서 빌드와 배포를 편리하게 한다.

        ㆍ빌드시 하나의 Jar를 사용하면서, 동시에 Fat Jar 문제도 해결한다.

        ㆍ지금까지 진행한 내장 톰캣 서버를 실행하기 위한 복잡한 과정을 모두 자동으로 처리한다.

     

    9. 스프링 부트와 웹 서버 - 실행 과정

    스프링 부트의 실행 과정

    @SpringBootApplication
    public class BootApplication {
        public static void main(String[] args) {
            SpringApplication.run(BootApplication.class, args);
        }
    }

    - 스프링 부트를 실행할 때는 자바 `main()` 메서드에서 `SpringApplication.run()` 을 호출해주면 된다.

    - 여기에 메인 설정 정보를 넘겨주는데, 보통 `@SpringBootApplication` 애노테이션이 있는 현재 클래스를 지정해주면 된다.

    - 참고로 현재 클래스에는 `@SpringBootApplication` 애노테이션이 있는데, 이 애노테이션 안에는 컴포넌트 스캔을 포함한 여러 기능이 설정되어 있다.

        ㆍ기본 설정은 현재 패키지와 그 하위 패키지 모두를 컴포넌트 스캔한다.

     

    핵심

    1. 스프링 컨테이너를 생성한다.

    2. WAS(내장 톰캣)를 생성한다.

    - 내장 톰캣에 디스패처 서블릿을 등록하고, 스프링 컨테이너와 연결해서 동작할 수 있게 한다.

     

    10. 스프링 부트와 웹 서버 - 빌드와 배포

    - JAR를 푼 결과를 보면 Fat Jar가 아니라 처음보는 새로운 구조로 만들어져 있다.

        ㆍ심지어 jar 내부에 jar를 담아서 인식하는 것이 불가능한데, jar가 포함되어 있고, 인식까지 되었다.

     

    *참고*

    - 빌드 결과를 보면 `boot-0.0.1-SNAPSHOT-plain.jar` 파일도 보이는데, 이것은 우리가 개발한 코드만 순수한 jar로 빌드한 것이다. 무시해도 된다.

     

    11. 스프링 부트 실행 가능 Jar

    *실행가능 Jar*

    - 스프링 부트는 이런 문제를 해결하기 위해 jar 내부에 jar를 포함할 수 있는 특별한 구조의 jar를 만들고 동시에 만든 jar를 내부 jar를 포함해서 실행할 수 있게 했다.

        ㆍ이것을 실행 가능 Jar(Executable Jar) 라 한다.

    - 문제 :  어떤 라이브러리가 포함되어 있는지 확인이 어렵다.

        ㆍ해결 : jar 내부에 jar를 포함하기 때문에 어떤 라이브러리가 포함되어 있는지 쉽게 확인할 수 있다.

    - 문제 : 파일명 중복을 해결할 수 없다.

        ㆍ해결 : jar 내부에 jar를 포함하기 때문에 `a.jar`, `b.jar` 내부에 같은 경로의 파일이 있어도 둘다 인식할 수 잇다.

     

    *Jar 실행정보*

    - java -jar xxx.jar 를 실행하면 우선 META-INF//MANIFEST.MF 파일을 찾는다.

    - Main-Class의 JarLauncher을 실행하여 jar 내부에 jar를 읽고, 또 특별한 구조에 맞게 클래스 정보도 읽은 후 Start-Class에 지정된 main()을 호출한다.

     

    *스프링 부트 로더*

    - `org/springframework/boot/loader` 하위에 있는 클래스들이다.

    - `JarLauncher`를 포함한 스프링 부트가 제공하는 실행 기능 Jar를 실제로 구동시키는 클래스들이 포함되어 있다.

        ㆍ스프링 부트는 빌드시에 이 클래스들을 포함해서 만들어 준다.

     

    *실행과정 정리*

    1. `java -jar xxx.jar`

    2. `MANIFEST.MF` 인식

    3. `JarLauncher.main()` 실행

        ㆍ`BOOT-INF/classes/` 인식

        ㆍ`BOOT_INF/lib/` 인식

    4. `BootApplication.main()` 실행

     

    * 참고 *

    - 실행가능 Jar가 아니라, IDE에서 직접 실행할 때는 `BootApplication.main()`을 바로 실행한다.

    - IDE가 필요한 라이브러리를 모두 인식할 수 있게 도와주기 때문에 `JarLauncher`가 필요하지 않다.

    댓글

Designed by Tistory.