Post

[Dev-core-backend] 자바 애플리케이션의 생성, 컴파일, 실행을 도와주는 도구 JDK와 배포 및 압축포맷

패키지와 모듈

🐀 패키지란 밀접하게 연관된 클래스(및 인터페이스)의 묶음이다

패키지란 클래스 파일(.class)을 포함하는 디렉토리이다.
그리고 모든 클래스는 반드시 하나의 패키지에 속해야 한다.
패키지를 지정하지 않는 모든 클래스는 자동적으로 이름없는 패키지에 속하게 된다.

모듈이란 밀접하게 연관된 패키지와 리소스의 묶음이다 결국, 모듈은 여러 개의 패키지를 묶어 한번 더 캡슐화 한것이다.
이로써 외부에 노출할 패키지와 은닉할 패키지를 정의할 수 있으며, 코드의 재사용성을 높일 수 있다.

즉, 모듈이란 패키지 관리 기능까지 포함된 라이브러리이다.

java9에서는 자바 플랫폼 전체를 모듈화하였다 즉, 자바 api를 많은 수의 모듈로 분할하여 컴파일할 때, 필요한 모듈들만으로 조립하여 구성할 수 있도록 했다.
🎯 자바 모듈화의 목적은 자바 컴포넌트들을 필요에 따라 조립하여 사용하기 위함이다.
세밀한 모듈화를 통해 시스템에 부하를 줄일 수 있다.

더불어, 모듈 기술자(module-info.java)를 통해 필요로 하는 의존모듈을 기술할 수 있고,
모듈간의 의존관계를 쉽게 파악할 수 있다.

JDK의 스펙과 구성요소

🐁 JDK (Java Development Kit) 로 프로그램을 생성, 컴파일, 실행할 수 있다

JavaSE (Java Platform, Standard Edition)
자바 개발부터 실행까지 모든 환경을 정의한 스펙을 말한다. 표준
JavaSE 스펙을 준수해서 만든 소프트웨어가 JDK이다.

JDK는 자바를 사용하기 위해 필요한 모든 기능을 갖춘 Java용 SDK (Software Development Kit)이다.
프로그램 개발에 필요한 기본 기능 및 응용 기능을 구현한 클래스와 인터페이스를 포함한 표준 패키지를 제공한다.
표준 패키지 내, 구현된 클래스와 선언된 인터페이스를 자바 API라고 한다.

JDK의 주요 패키지

  • java.lang
    문자열, 입출력 등과 같은 기본적인 클래스 및 인터페이스 제공 자동 import
  • java.util
    날짜, 시간, 해시맵 등의 유틸리티 클래스 및 인터페이스
  • java.awt
    GUI 프로그래밍 시 필요한 클래스 및 인터페이스

또한, JDK는 JRE + 컴파일러(javac.exe)를 포함하고 있다.
그리고 JRE (Java Runtime Environment)JVM + 자바 클래스 라이브러리로 구성되어 있다.
즉, JRE는 자바 런타임 환경(실행)을 제공한다.

때문에 JDK로 프로그램을 생성, 컴파일, 실행할 수 있다.

자바 라이브러리와 jar파일

🍝 자바의 라이브러리는 .jar (java application archive) 압축파일 형태로 존재한다

jar파일은 자바에서 사용되는 특정 유형의 압축(아카이브) 포맷이다.
즉, 자바 프로젝트를 압축한 파일이다.
※ zip과 동일한 보관 및 압축기술을 사용한다.

이러한 .jar파일은 JRE만 가지고도 구동가능하기 때문에, .jar 압축포맷으로 라이브러리를 쉽게 배포할 수 있다.

📕 jar파일과 META-INF 폴더
jar파일은 항상 META-INF 폴더가 포함되는데, 이는 메타데이터 파일이 저장되는 경로이다.
MANIFEST.MF 파일은 jar파일로 패키징된 파일에 대한 정보를 포함하는 특수 파일이다.
KEY/VALUE 형태로 작성되어 있으며,
출처 추적, 변조 방지 등 추가정보 제공에 목적이 있다.

WAS 위에서 구동되는 war파일

🍝 .war (web application archive)파일은 웹 관련 자원을 포함한 압축(아카이브) 포맷이다

단순하게, 웹 애플리케이션 압축 파일 포맷이다.
✨ 웹 애플리케이션을 구성할 때 필요한 모든 요소를 하나의 아카이브로 묶어 압축한 jar파일이다.

이러한 war파일은 톰캣과 같은 웹 컨테이너가 있어야 구동가능하다.

📘 war파일과 사전정의된 구조
war 포맷은 원하는 구성을 할 수 있는 jar 포맷과 달리
META-INF, WEB-INF 디렉토리 같은 사전정의된 구조를 사용하며
WEB-INF 디렉토리 안에는 배포 디스크립터 web.xml가 담겨있다.

스프링과 스프링부트의 차이

🐙 스프링과 스프링부트의 차이

(1) dependency 관리
🌱 스프링dependency를 설정 시, 설정파일이 상대적으로 길고,
모든 dependency에 대해 버전관리도 일일이 해줘야 한다.

🪴 스프링부트dependency를 보다 쉽게 설정할 수 있다.
또한, 필요한 모든 dependency를 자동으로 추가하고, 버전관리도 자동으로 해준다.


(2) Configuration 설정
🌱 스프링Configuration 설정 시, 설정 파일이 상대적으로 길고,
모든 어노테이션 및 빈 등록을 해줘야 한다.

🪴 스프링부트application.yml 파일에 간단하게 설정하면 된다.
또한, @SpringBootApplication에는 @ComponentScan@EnableAutoConfiguration이 포함되어 있는데,
@ComponentScan은 특정 어노테이션이 붙은 객체들을 스캔해 자동으로 Bean에 등록해주고
@EnableAutoConfiguration은 컴포넌트 스캔 이후, 사전에 정의한 라이브러리들을 Bean에 등록해준다.
즉, 빈등록이 간편하다.
해당 어노테이션 덕분에 외부 라이브러리 및 내장 톰캣 서버 등이 실행될 수 있다.


(3) Embeded Tomcat
🌱 스프링으로 개발한 애플리케이션의 경우,
war 파일을 외부 WAS에 담고, 모든 설정을 마쳐 배포했다.

🪴 스프링부트는 내장 톰캣을 가지고 있기 때문에 별다른 설정없이 jar파일로 간편하게 배포할 수 있다.

스프링부트와 jar 압축포맷

🌋 스프링부트를 사용한다면 jar 압축포맷을 사용하여 서비스하는 것이 좋다

jar 압축포맷이나 war 압축포맷이나 애플리케이션을 쉽게 배포하고 동작하도록
관련 파일들을 패키징해주는 것이 주역할이다.

다만, jar파일은 모든 의존성을 내장하고 있어 독립실행이 가능하다.
스프링부트는 내장 서버(톰캣)을 포함해서 웹 애플리케이션을 jar파일로 패키징한다.
그러면 별도의 서버 설치 없이 독립적으로 실행할 수 있다.
MSA(Micro Service Architecture)에 적합하다.

☄️ 스프링부트의 jar구성 및 실행원리

java -jar PROJECT_NAME.jar
jar실행 시, spring-boot-loader가 우리의 소스코드를 호출한다. spring-boot-loader🐘 gradle이 빌드할 때 디폴트로 넣어준다.

🪶 굳이 spring-boot-loader를 통해, jar를 실행해주는 이유
자바에도 jar를 실해해주는 클래스가 있을텐데, spring-boot-loader를 통해 실행하는 이유는
자바는 nested jar를 로드하는 방식을 제공하고 있지 않은데,
스프링부트는 spring-boot-loader라는 자신만의 방식으로 nested jar까지 로드하는 방법을 제공하기 때문이다.

그러면 📂 build/libs 폴더에 PROJECT_NAME.jar 파일이 생성된다.
해당 jar파일에는 스프링부트로 우리의 소스코드를 실행시키는데 필요한 모든 것이 들어있다.

1
2
3
4
5
6
7
8
PROJECT_NAME.jar
 - BOOT-INF
    - classes
    - lib
    - classpath.idx
    - layers.idx
 - META-INF
    - MANIFEST.MF
  • BOOT-INF : 우리가 개발한 소스코드 영역

    • classes : JVM이 읽을 수 있도록 컴파일된 클래스 파일(.class)이 존재
    • lib : 코드실행에 필요한 dependency 라이브러리가 존재
    • classpath.idx : 스프링부트가 lib에 있는 외부 라이브러리를 찾을 수 있도록 명시
    • layers.idx : 도커에서 jar 이미지를 만들 때 필요한 레이어 정보
  • META-INF : 스프링부트와 우리가 개발한 소스코드를 연결해주는 영역
    MANIFEST.MFMain-ClassJarLauncher를 호출
    ⚠️ JarLauncher.java 클래스에는 main 메서드가 존재한다.
    해당 메서드에서 최상위 부모 Launcher.java 클래스의 launch(args) 메서드를 호출한다.

    JarLauncherStart-ClassPROJECT_NAMEApplication을 호출
    ⚠️ 프레임워크가 우리의 소스코드를 대신 호출해준다. (🎳 항상 프레임워크에게 흐름 통제권이 있다.)

☄️ JSP는 일반적으로 📂 src/main/webapp/WEB-INF/jsp에 위치한다.
문제는 jar파일로 패키징했을 때, 🐖 그 구성에 WEB-INF 폴더가 없다는 것이다.
즉, JSP가 build시 포함되지 않는다.
해당 문제는 META-INF 폴더를 이용해서 해결할 수 있다.
META-INF는 스프링부트에서 빌드 시, 추가적으로 필요한 resource들을 담아주는 역할을 하는데
📂 src/main/resources/META-INF/resources/WEB-INF 해당 경로에 JSP를 넣어주면 된다.
webapp 하위에 잇는 WEB-INF를 지워준다.
이렇게 한 뒤 jar 파일로 패키징하면 JSP 템플릿 프레임워크를 동작시킬 수 있다.
📕 ClassPath
ClassPath는 컴파일러나 JVM이 클래스 위치를 찾는데 사용되는 경로이다.
%JAVA_HOME%lib
🍪 일반적으로 스프링 프레임워크에서는 war파일을 생성해서 외부 WAS(톰캣 etc..)에 배포하곤 했다.
톰캣과 같은 웹 컨테이너에 war파일을 올리면 톰캣이 애플리케이션을 실행시켜준다.
이와 같은 배포 방식은 서버의 기능을 최대한 활용할 수 있기 때문에 대규모 및 복잡한 애플리케이션에서 유리하다.
This post is licensed under CC BY 4.0 by the author.