메인 컨텐츠로 가기

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관 보기.

developerWorks에 처음 로그인하면 developerWorks프로파일이 생성됩니다.귀하의 프로파일에서 동의하신 내용이 공개되지만 이 사항은 언제든지 변경 가능합니다. 귀하의 성명(숨김으로 체크되어 있어도 표시됩니다)과 디스플레이 이름은 게시한 컨텐츠나 사이트 엑세스시 표시됩니다.

모든 정보가 안전하게 전송되었습니다.

  • 닫기 [x]

처음 developerWorks에 로그인할 때 프로파일이 작성되므로, 이를 위해 디스플레이 이름을 선택해야 합니다. 선택하신 디스플레이 이름은 developerWorks에 게시한 컨텐츠에 표시됩니다.

3글자 이상 31글자 이하의 길이로 사용 가능합니다. dW커뮤니티 내에서는 보안상 이메일주소를 제외한 다른 이름을 지정하셔야 합니다.

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관 보기.

모든 정보가 안전하게 전송되었습니다.

  • 닫기 [x]

JAR에 대해 모르고 있던 5가지 사항

클래스 번들 이상의 Java Archive

Ted Neward, Principal, Neward & Associates
Ted Neward는 글로벌 컨설팅 업체인 ThoughtWorks의 컨설턴트이자 Neward & Associates의 회장으로 Java, .NET, XML 서비스 및 기타 플랫폼에 대한 컨설팅, 조언, 교육 및 강연을 한다. 워싱턴 주의 시애틀 근교에 살고 있다.

요약:  많은 Java™ 개발자들이 JAR의 기본 기능만을 사용하고 있습니다. 단순히 JAR을 사용하여 클래스를 번들로 묶어서 프로덕션 서버로 전달하고 있을 뿐입니다. 하지만 JAR은 단순히 이름이 바뀐 ZIP 파일에 그치지 않고 그 이상의 기능을 제공합니다. Spring 종속성 및 구성 파일을 jar로 작성하는 방법에 대한 팁을 비롯하여 Java Archive 파일을 최대한으로 활용하는 방법에 대해 살펴봅니다.

원문 게재일:  2010 년 6 월 15 일 번역 게재일:   2010 년 8 월 03 일
난이도:  초급 영어로:  보기 PDF:  A4 and Letter (36KB | 10 pages)Get Adobe® Reader®
페이지뷰:  6486 회
의견:  


대부분의 Java 개발자에게 JAR 파일과 그 특별한 사촌인 WAR 및 EAR은 단순히 장기적인 Ant 또는 Maven 프로세스의 최종 결과에 불과하다. 일반적으로 JAR을 서버(또는 드물게 사용자의 시스템)의 올바른 위치에 복사한 다음 잊어버린다.

실제로 JAR은 소스 코드를 저장하는 것 이상의 작업을 수행할 수 있지만 사용자가 가능한 작업과 작업 요청 방법을 알아야 한다. 5가지 사항 시리즈의 이 기사에서 제공하는 팁에서는 Java Archive 파일(및 WAR와 EAR)을 특히, 배치 시간에 최대한으로 활용하는 방법에 대해 설명한다.

많은 Java 개발자가 Spring을 사용하고 있고 Spring 프레임워크에서 일반적인 JAR 사용 방법이 문제가 되는 경우가 있기 때문에 일부 팁에서는 특별히 Spring 애플리케이션에서 JAR을 사용하는 방법에 대해 설명한다.

이 시리즈의 정보

Java 프로그래밍에 대해 알고 있다고 생각하는가? 하지만 실제로는 대부분의 개발자가 작업을 수행하기에 충분할 정도만 알고 있을 뿐 Java 플랫폼에 대해서는 자세히 알고 있지 않다. 이 시리즈에서 Ted Neward는 Java 플랫폼의 핵심 기능에 대한 자세한 설명을 통해 까다로운 프로그래밍 과제를 해결하는 데 도움이 되는 알려져 있지 않은 사실을 밝힌다.

먼저 이후 팁에서 기본적으로 사용할 표준 Java Archive 파일 프로시저를 보여 주는 간단한 예제를 살펴보자.

JAR로 저장하기

일반적으로 코드 소스를 컴파일한 후 jar 명령행 유틸리티 또는 더 일반적으로 Ant jar 태스크를 통해 Java 코드(패키지별로 구분됨)를 단일 콜렉션으로 수집하여 JAR 파일을 빌드한다. 이 프로세스는 매우 간단하기 때문에 여기에서는 다루지 않겠지만 이 기사의 뒷부분에서 JAR의 생성 방법에 대한 주제를 다시 살펴볼 것이다. 지금은 단지 메시지를 콘솔에 인쇄하는 매우 유용한 태스크를 수행하는 독립형 콘솔 유틸리티인 Hello를 아카이브해야 한다(Listing 1 참조).


Listing 1. 콘솔 유틸리티 아카이브하기
package com.tedneward.jars;

public class Hello
{
    public static void main(String[] args)
    {
        System.out.println("Howdy!");
    }
}

Hello 유틸리티는 거창하지는 않지만 코드를 실행하여 JAR 파일을 탐색하기에 유용한 골격이다.


1. JAR은 실행 파일이다.

.NET, C++ 등의 언어는 역사적으로 OS 친화적인 장점을 가지고 있다. 즉, 명령행에서 단순히 해당 이름을 참조하거나(helloWorld.exe) GUI 쉘에서 해당 아이콘을 두 번 클릭하여 애플리케이션을 실행할 수 있다. 하지만 Java 프로그래밍에서는 실행 애플리케이션인 java가 JVM을 프로세스로 부트스트랩하고, 사용자가 실행할 main() 메소드가 있는 클래스를 나타내는 명령행 인수(com.tedneward.Hello)를 전달해야 한다.

이러한 추가 단계로 인해 Java에서는 사용자 친화적인 애플리케이션을 작성하기가 더 어렵다. 일반 사용자가 이러한 모든 요소를 명령행에 입력해야 한다. 하지만 이 작업은 많은 일반 사용자가 원하지 않는 것이다. 게다가 키보드를 잘못 눌러서 모호한 오류가 발생할 수도 있다.

이 문제를 해결하는 방법은 JAR 파일을 "실행 파일"로 만드는 것이다. 즉, Java 실행 프로그램이 JAR 파일을 실행할 때 시작할 클래스를 자동으로 인식할 수 있도록 만들면 된다. 이를 위해서는 다음과 같이 JAR 파일의 매니페스트(JAR의 META-INF 서브디렉토리에 있는 MANIFEST.MF)에 항목을 추가하면 된다.


Listing 2. 시작점 알려주기
Main-Class: com.tedneward.jars.Hello

매니페스트는 이름/값 쌍으로 구성된 세트이다. 매니페스트에서는 캐리지 리턴과 공백으로 인해 문제가 발생할 수도 있기 때문에 JAR을 빌드할 때 Ant를 사용하여 매니페스트를 생성하는 방법이 가장 쉬운 방법이다. Listing 3에서는 Ant jar 태스크의 manifest 요소를 사용하여 매니페스트를 지정한다.


Listing 3. 시작점 빌드하기
    <target name="jar" depends="build">
        <jar destfile="outapp.jar" basedir="classes">
            <manifest>
                <attribute name="Main-Class" value="com.tedneward.jars.Hello" />
            </manifest>
        </jar>
    </target>

이제 사용자는 java -jar outapp.jar을 통해 명령행에서 파일 이름을 지정하는 것만으로도 JAR 파일을 실행할 수 있다. 일부 GUI 쉘에서는 JAR 파일을 두 번 클릭하여 실행할 수도 있다.


2. JAR은 종속성 정보를 포함할 수 있다.

Hello 유틸리티의 단어가 너무 많이 사용되고 있기 때문에 구현을 변경할 필요성이 제기되고 있다. Spring 또는 Guice와 같은 DI(Dependency Injection) 컨테이너가 많은 세부 사항을 자동으로 처리하기는 하지만 DI 컨테이너의 사용을 포함하도록 코드를 수정할 경우 Listing 4와 같은 결과가 발생할 수 있다는 문제점이 아직도 남아 있다.


Listing 4. Hello, Spring world!
package com.tedneward.jars;

import org.springframework.context.*;
import org.springframework.context.support.*;

public class Hello
{
    public static void main(String[] args)
    {
        ApplicationContext appContext =
            new FileSystemXmlApplicationContext("./app.xml");
        ISpeak speaker = (ISpeak) appContext.getBean("speaker");
        System.out.println(speaker.sayHello());
    }
}

Spring에 대한 추가 정보

이 팁에서는 독자가 종속성 주입 및 Spring 프레임워크에 익숙하다고 간주하고 있다. 두 주제에 대해 자세히 알고 싶으면 참고자료 섹션을 참조하기 바란다.

실행 프로그램에 대한 -jar 옵션은 -classpath 명령행 옵션의 내용을 겹쳐쓰기 때문에 이 코드를 실행할 때 Spring이 CLASSPATH 환경 변수에 있어야 한다. 다행스럽게도 JAR에서는 매니페스트에 표시할 다른 JAR 종속성을 선언할 수 있다. 이렇게 하면 사용자가 선언하지 않아도 CLASSPATH가 암묵적으로 작성된다(Listing 5 참조).


Listing 5. Hello, Spring CLASSPATH!
    <target name="jar" depends="build">
        <jar destfile="outapp.jar" basedir="classes">
            <manifest>
                <attribute name="Main-Class" value="com.tedneward.jars.Hello" />
                <attribute name="Class-Path" 
                    value="./lib/org.springframework.context-3.0.1.RELEASE-A.jar 
                      ./lib/org.springframework.core-3.0.1.RELEASE-A.jar 
                      ./lib/org.springframework.asm-3.0.1.RELEASE-A.jar 
                      ./lib/org.springframework.beans-3.0.1.RELEASE-A.jar 
                      ./lib/org.springframework.expression-3.0.1.RELEASE-A.jar 
                      ./lib/commons-logging-1.0.4.jar" />
            </manifest>
        </jar>
    </target>

Class-Path 속성에는 애플리케이션에서 사용하는 JAR 파일에 대한 상대 참조가 있다. 이 참조는 절대 참조로 작성하거나 접두부 없이 작성할 수 있으며, 이 경우 JAR 파일은 애플리케이션 JAR과 같은 디렉토리에 있는 것으로 간주된다.

아쉽게도 Ant Class-Path 속성에 대한 value 속성은 한 행으로 표시되어야 한다. 왜냐하면 JAR 매니페스트가 여러 Class-Path 속성을 처리하지 못하기 때문이다. 따라서 이러한 모든 종속성은 매니페스트 파일에 한 행으로 표시되어야 한다. 물론 보기에 좋지는 않지만 java -jar outapp.jar을 사용할 수 있기에 그 가치는 충분하다고 할 것이다.


3. JAR은 암묵적으로 참조될 수 있다.

Spring 프레임워크를 사용하는 여러 다양한 명령행 유틸리티(또는 기타 애플리케이션)가 있다면 모든 유틸리티에서 참조할 수 있는 공통 위치에 Spring JAR 파일을 저장하여 효율을 높일 수 있다. 이렇게 하면 전체 파일 시스템 내에서 JAR 사본을 여러 개 유지하지 않아도 된다. Java 런타임에서 JAR에 대한 공통 위치로 사용하는 "확장 디렉토리"는 기본적으로 설치된 JRE 경로 아래의 lib/ext 서브디렉토리에 있다.

JRE는 사용자 정의할 수 있는 위치이지만 지정된 Java 환경 내에서 사용자 정의되는 경우가 거의 없기 때문에 lib/ext가 JAR을 저장하기에 안전한 위치이고 Java 환경의 CLASSPATH에서 JAR을 암묵적으로 사용할 수 있다고 생각해도 무방하다.


4. Java 6에서는 클래스 경로 와일드카드를 사용할 수 있다.

CLASSPATH 환경 변수(몇 년 전에 Java 개발자가 남겨 두어야 했던)와 명령행 -classpath 매개변수가 많아지는 것을 피하기 위해 Java 6에서는 클래스 경로 와일드카드라는 개념이 도입되었다. 클래스 경로 와일드카드를 사용하면 인수에 명시적으로 나열된 모든 JAR 파일을 하나하나 실행할 필요 없이 lib/*와 해당 디렉토리에 나열된 모든 JAR 파일(재귀적이지 않음)을 클래스 경로에 지정할 수 있다.

아쉽게도 클래스 경로 와일드카드는 앞에서 설명한 Class-Path 속성 매니페스트 항목에 적용되지 않는다. 하지만 코드 생성 도구 또는 분석 도구와 같은 개발자 태스크를 위한 Java 애플리케이션(서버 포함)을 쉽게 실행할 수 있다.


5. JAR에는 코드 이상의 것이 담겨 있다.

Java 에코시스템의 많은 부분과 마찬가지로 Spring도 환경의 설정 방법을 설명하는 구성 파일을 사용한다. 즉, Spring에서는 JAR 파일과 같은 디렉토리에 있는 app.xml 파일을 사용한다. 하지만 대부분의 개발자는 구성 파일을 JAR 파일과 함께 복사하는 것을 잊어버린다.

일부 구성 파일은 시스템 관리자가 편집할 수 있지만 하이버네이트 맵핑과 같은 상당 수의 구성 파일은 시스템 관리자 도메인의 외부에 있기 때문에 배치 작업 중에 발생하는 문제의 원인이 되고 있다. 합리적인 해결 방법은 구성 파일과 코드를 함께 패키지하는 것이다. 이는 JAR이 기본적으로 외형 상 ZIP 형식으로 되어 있기 때문에 가능한 방법이다. JAR을 빌드할 때 구성 파일을 Ant 태스크나 jar 명령행에 포함시키면 된다.

JAR은 구성 파일뿐만 아니라 다른 유형의 파일도 포함할 수 있다. 예를 들어, 필자는 특성 파일에 액세스할 필요가 있는 SpeakEnglish 컴포넌트를 Listing 6과 같이 설정했다.


Listing 6. 임의로 응답하기
package com.tedneward.jars;

import java.util.*;

public class SpeakEnglish
    implements ISpeak
{
    Properties responses = new Properties();
    Random random = new Random();

    public String sayHello()
    {
        // Pick a response at random
        int which = random.nextInt(5);
        
        return responses.getProperty("response." + which);
    }
}

responses.properties를 JAR 파일에 넣는다는 것은 JAR 파일과 함께 배치할 파일이 하나 이상 있다는 것을 의미한다. 이 작업을 수행하려면 JAR 단계 동안 responses.properties 파일을 포함시켜야 한다.

특성을 JAR에 저장한 후 특성을 다시 가져오는 방법이 궁금할 수도 있을 것이다. 원하는 데이터가 동일한 JAR 파일 내에 함께 있는 경우에는 이전 예제에서 보았듯이 JAR 파일의 위치를 확인한 후 JarFile 오브젝트를 사용하여 JAR 파일을 열려고 시도하지 않아도 된다. 대신 ClassLoader getResourceAsStream() 메소드를 사용하여 클래스의 ClassLoader를 통해 JAR 파일 내에서 특성을 "자원"으로 찾는다(Listing 7 참조).


Listing 7. ClassLoader가 자원을 찾는다.
package com.tedneward.jars;

import java.util.*;

public class SpeakEnglish
    implements ISpeak
{
    Properties responses = new Properties();
    // ...

    public SpeakEnglish()
    {
        try
        {
            ClassLoader myCL = SpeakEnglish.class.getClassLoader();
            responses.load(
                myCL.getResourceAsStream(
                    "com/tedneward/jars/responses.properties"));
        }
        catch (Exception x)
        {
            x.printStackTrace();
        }
    }
    
    // ...
}

구성 파일, 오디오 파일, 그래픽 파일 등을 포함한 모든 유형의 자원에 대해 이 프로시저를 수행할 수 있다. 실제로 모든 파일 유형을 JAR로 묶고, InputStream으로 가져온(ClassLoader를 통해) 다음 원하는 방식으로 사용할 수 있다.


결론

이 기사에서는 적어도 역사와 필자의 경험을 바탕으로 대부분의 Java 개발자가 JAR에 대해 모르고 있던 5가지 주요 사항을 살펴보았다. 이러한 JAR 관련 팁은 모두 WAR에도 동일하게 적용된다. WAR의 경우에는 서블릿 환경이 디렉토리의 전체 내용을 선택하고 사전 정의된 시작점이 있기 때문에 일부 팁(특히, Class-PathMain-Class 속성)의 중요성이 낮을 수 있다. 하지만 전체적인 관점에서 이러한 팁은 "좋아, 이 디렉토리의 모든 항목을 복사하는 작업부터 시작하자..."라는 패러다임을 극복할 수 있도록 도와 준다. 결과적으로 Java 애플리케이션을 훨씬 더 간단하게 배치할 수도 있다.

이 시리즈의 다음 기사에서는 Java 애플리케이션의 성능 모니터링에 대해 모르고 있던 5가지 사항에 대해 살펴본다.



다운로드 하십시오

설명이름크기다운로드 방식
Sample code for this articlej-5things6-src.zip10KBHTTP

다운로드 방식에 대한 정보


참고자료

교육

  • 5 things you didn't know about ...(Ted Neward 저, developerworks): 이 새 시리즈는 Java의 사소한 기능에 큰 가치를 부여한다.

  • "JAR 파일"(Pagadala Suresh 및 Palaniyappan Thiagarajan 저, developerWorks, 2003년 10월): 패키징, 실행 가능한 JAR 파일, 보안 및 색인을 포함한 Java Archive 형식의 특징과 장점에 대해 소개한다.

  • Packaging programs in JAR files(The Java Tutorials trail): JAR에 대한 기본적인 정보를 볼 수 있다.

  • Spring: 소스를 통해 직접 이 강력하고 유연하며 유명한 프레임워크에 대한 정보를 볼 수 있다.

  • "Dependency injection with Guice"(Nicholas Lesiecki 저, developerworks, 2008년 12월): DI는 관리성, 테스트 가능성 및 유연성을 높여 주며, Guice는 DI를 쉽게 사용할 수 있도록 지원한다.

  • "Setting multiple jars in java classpath"(StackOverflow Q&A, 마지막 갱신 날짜: 2010년 3월): 클래스 경로 와일드카드에 대한 자세한 정보를 볼 수 있다.

  • "See JARs run"(Shawn Silverman 저, JavaWorld.com, 2002년 5월): 이 튜토리얼에서는 실행 가능한 JAR 파일을 작성하는 방법에 대해 자세히 설명한다.

  • "Advanced topics in programming languages series: JSR 277: Java Module System"(Google Tech Talks, 2007년 5월): JAR에는 클래스 경로, JAR 파일, 확장 등과 관련된 단점이 있다. 이 Google Tech Talk에서는 JSR 277이 이러한 단점을 해결하는 방법에 대해 설명한다.

  • developerWorks Java 기술 영역: Java 프로그래밍과 관련된 모든 주제를 다루는 여러 편의 기사를 찾아보자.

토론

필자소개

Ted Neward는 글로벌 컨설팅 업체인 ThoughtWorks의 컨설턴트이자 Neward & Associates의 회장으로 Java, .NET, XML 서비스 및 기타 플랫폼에 대한 컨설팅, 조언, 교육 및 강연을 한다. 워싱턴 주의 시애틀 근교에 살고 있다.

잘못된 도움말 신고

부정사용 신고

감사합니다. 이 항목은 운영자가 관심을 표시했습니다.


잘못된 도움말 신고

부정사용 신고

제출실패 신고. 나중에 다시 실행해주세요.


디벨로퍼웍스 로그인


IBM ID가 필요하세요?
IBM ID를 잊으셨습니까?


비밀번호를 잊으셨습니까?
비밀번호 변경

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관.

 


developerWorks에 처음 로그인하면 developerWorks프로파일이 생성됩니다.귀하의 프로파일에서 동의하신 내용이 공개되지만 이 사항은 언제든지 변경 가능합니다. 귀하의 성명(숨김으로 체크되어 있어도 표시됩니다)과 디스플레이 이름은 게시한 컨텐츠나 사이트 엑세스시 표시됩니다.

화면상에 보여지는 닉네임을 정하세요.

처음 developerWorks에 로그인할 때 프로파일이 작성되므로, 이를 위해 디스플레이 이름을 선택해야 합니다. 선택하신 디스플레이 이름은 developerWorks에 게시한 컨텐츠에 표시됩니다.

3글자 이상 31글자 이하의 길이로 사용 가능합니다. dW커뮤니티 내에서는 보안상 이메일주소를 제외한 다른 이름을 지정하셔야 합니다.

3개의 &이나 대쉬를 포함해주시고 31글자내로 제한해주세요.


developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관.

 


아티클 순위

의견

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=20
Zone=자바
ArticleID=503042
ArticleTitle=JAR에 대해 모르고 있던 5가지 사항
publish-date=06152010
author1-email=ted@tedneward.com
author1-email-cc=

태그

Help
검색 필드를 사용하여 My developerWorks 내에서 해당 태그가 사용된 모든 종류의 컨텐츠를 검색하십시오.

태그를 더 많이 보거나 적게 보기 위해 슬라이더 막대를 사용하십시오.

인기 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 최고 인기 태그를 보여줍니다.

내 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 귀하의 태그를 보여줍니다.

검색 필드를 사용하여 My developerWorks 내에서 해당 태그가 사용된 모든 종류의 컨텐츠를 검색하십시오. 인기 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 최고 인기 태그를 보여줍니다. 내 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 귀하의 태그를 보여줍니다.