스프링부트 생성 배경 - 내장톰켓 , FatJar,Executable Jar

Shaun·2023년 3월 7일
1

SpringBoot

목록 보기
17/20
post-thumbnail

스프링부트의 장점을 알아보기위해 저번시간에 부트의 내장 톰켓을 사용하지않고 톰켓을 직접깔고,서블릿,서블릿컨테이너, 스프링컨테이너, 디스패쳐서블릿 과 스프링컨테이너 연결 까지 해봤다.

이제 부트의 장점중 하나인 내장톰켓에 대해 알아보자

내장톰켓

나오게 된 배경(WAR)

  • 기존 톰켓은 따로 설치해줘야하며 버전관리도 해야함
  • 톰켓을 on/off 해줘야함
  • WAR로 빌드해 WAS에 일일이 다 올려줘야함

내장톰켓

  • main 메서드만 실행하면 웹서버 까지 자동실행
  • 톰켓도 하나의 라이브러리로 만들어 내장 시켜버림
  • JAR 안에 다양한 라이브러리+ 내장톰켓
public static void main(String[] args) throws LifecycleException { System.out.println("EmbedTomcatServletMain.main");
//톰캣 설정
Tomcat tomcat = new Tomcat();
          Connector connector = new Connector();
          connector.setPort(8080);
          tomcat.setConnector(connector);
          
//서블릿 등록
Context context = tomcat.addContext("", "/");
            tomcat.addServlet("", "helloServlet", new HelloServlet());
            context.addServletMappingDecoded("/hello-servlet", "helloServlet");
            tomcat.start();
}
  • 내장 톰켓은 딱히 어려운게 없다. 커넥터로 포트를 열고 서블릿을 등록 해준다

내장톰켓+ 스프링연동

public static void main(String[] args) throws LifecycleException { System.out.println("EmbedTomcatSpringMain.main");

//톰캣 설정
Tomcat tomcat = new Tomcat();
          Connector connector = new Connector();
          connector.setPort(8080);
          tomcat.setConnector(connector);
          
//스프링 컨테이너 생성
AnnotationConfigWebApplicationContext appContext = newAnnotationConfigWebApplicationContext();
appContext.register(HelloConfig.class); 

//스프링 MVC 디스패처 서블릿 생성, 스프링 컨테이너 연결
DispatcherServlet dispatcher = new DispatcherServlet(appContext);

//디스패처 서블릿 등록
Context context = tomcat.addContext("", "/"); 
tomcat.addServlet("", "dispatcher", dispatcher); 
context.addServletMappingDecoded("/", "dispatcher");
tomcat.start();**텍스트**
      }
  • 저번에 스프링컨테이너와 디스패처 서블릿을 연결하는 코드 + 내장톰켓 코드이다. 별로 어려운건 없다
  • 이로서 Main메서드 하나가지고 웹서버,디스패처서블릿, 스프링 컨테이너 등등 모든 설정을 만들수 있다.

빌드 와 배포

JAR

  • main 메서드를 실행하기 위해서는 jar로 빌드 해야함

  • jar 로 코드를 추출시 META-INF/MANIFEST.MF 에 실행할 main메서드의 클래스를 지정해줘야한다.

JAR 특징

  • 이 상태로 그냥 빌드하고 실행시켜보면 java.lang.NoClassDefFoundError 가 발생 할것이다.
  • JAR와 WAR의 차이점은 WAR는 빌드시 내장톰켓 라이브러리를 포함하지만 JAR는 포함하지 않는다.

JAR는 JAR파일을 포함할수 없다

  • WAR와 다르게 JAR는 라이브러리 역활을 하는 JAR를 포함할 수 없다.

Fat JAR

  • 말 그대로 라이브러리 포함 문제를 해결하기 위해 나온 뚱뚱한 JAR
  • JAR를 풀면 class들이 나온다. 이 class들을 가져와 다시 빌드한 JAR에 포함하는 방법

단점

  • 라이브러리들을 모두 class로 풀어놨으니 어떤 라이브러리가 사용되고 있는지 추적이 힘듬
  • 클래스나 리소스 명이 같으면 충돌함으로 둘중에 하나만 실행됨
    -> 그래서 나온게 부트 클래스!

부트 클래스

 public static void run(Class configClass, String[] args) {

//내장톰켓설정 코드
..

//스프링 컨테이너 설정 코드
AnnotationConfigWebApplicationContext appContext = new
AnnotationConfigWebApplicationContext();
appContext.register(configClass);

//디스패처 서블릿, 스프링 컨테이너 연결 코드
.. 
//디스패처 서블릿 -> 서블릿 컨테이너에 등록 코드
..
}
 @Target(ElementType.TYPE)
  @Retention(RetentionPolicy.RUNTIME)
  @Documented
  @ComponentScan
  public @interface MySpringBootApplication {
  }
  • configClass : 스프링 설정을 파라미터로 전달받음
  • args: main(args) 를 전달 받아서 사용
  • 컴포넌트 스캔이 추가된 애노테이션 ,
  • 기존 코드와는 다르게 스프링컨테이너 설정 코드에서 configClass 를 받고있음.

메인 메서드

@MySpringBootApplication
  public class MySpringBootMain {
      public static void main(String[] args) {
          System.out.println("MySpringBootMain.main");
          MySpringApplication.run(MySpringBootMain.class, args);
}
  • 방금 만든 애노테이션의 적용으로 이 애노테이션이 붙은 클래스의 현재 패키지 부터 그 하위 패키지를 컴포넌트 스캔의 대상으로함
  • 단 두가지 애노테이션, run(), 으로내장 톰캣 실행, 스프링 컨테이너 생성, 디스패처 서블릿, 컴포넌트 스캔 완료
    • 애노테이션으로 컴포넌트 스캔뒤, 그것들을 run(configClass) 인자로 넘겨서 스프링컨테이너에 넣어줌


  • 우리가 직접 사용하는 스프링부트 메인메서드와 비교해보면 매우 흡사하다.
  • 이 메인 메서드 코드에는 WAS내장톰켓, 스프링컨테이너 스캔, 생성, 디스패처 서블릿 생성,연결 역활을 한다.

내장톰켓 빌드,배포(실행가능 Jar)

  • Jar는 또다른 Jar(라이브러리) 를 포함하지 못하는데 스프링부트에서는 fatJar 문제를 어떻게 해결 했을까?

실행가능 Jar

  • jar 내부에 jar를 포함할 수 있는 특별한 구조의 jar를 만들고 동시에 만든 jar를 내부 jar를 포함해서 실행할 수 있게 했다. 이것을 실행 가능 Jar(Executable Jar)라 한다.

  • jar안에 jar를 넣는 구조라 무슨 라이브러리가 들어왔는지 파악 가능하며, 같은 경로에 파일이 있어도 파악 가능

실행가능 Jar 내부구조

  • build 후 jar 실행
    -> META-INF/MANIFEST.MF 에서 MainClass -> Main메서드 실행
Manifest-Version: 1.0
  Main-Class: org.springframework.boot.loader.JarLauncher
  Start-Class: hello.boot.BootApplication
  Spring-Boot-Version: 3.0.2
  Spring-Boot-Classes: BOOT-INF/classes/
  Spring-Boot-Lib: BOOT-INF/lib/
  Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
  Spring-Boot-Layers-Index: BOOT-INF/layers.idx
  Build-Jdk-Spec: 17
  • 하지만 실제로 MAINFEST.MF코드에 들어가보면 예상했던 main메서드가 있는 class 가 아닌 JarLauncher이 실행 됀다.

  • JarLauncher 은 스프링부트가 넣어준 것이며 스프링부투는 fatJar를 개선하기 위해 jar를 포함할수 있는 특별한 구조의 jar를 만들어 놓는다고 했다. 바로 JarLauncher가 이 특별한 구조를 읽는 장치다. 그 뒤로 우리가 예상했던 main 메서드 실행!

  • JarLauncher - >Main메서드

IDE

  • IDE에서 사용하는 경우에는 필요한 라이브러리를 모두 인식할수 있어 따로 JarLauncher가 필요 없다
profile
호주쉐프에서 개발자까지..

0개의 댓글