java로 프로그래밍을 하다가 보면 몇가지 설정값을 외부에서 받아야 하는 경우가 있는데 이때 사용하는 것이 property 파일이다.

jdk에도 이 프로퍼티 파일을 다룰 수 있는 클래스가 마련되어 있다. java.util.Properties 클래스가 그 용도이다.

이 클래스를 사용하려면 load라는 메소드를 통해서 프로퍼티 파일일 읽어 와야 하는데 이때 전달되는 인자는 InputStream이다.

문제는 이 InputStream을 전달하려면 FileInputStream을 만들어서 전달해야 하는데 이 FileInputStream을 생성하려면 그 프로퍼티 파일의 경로를 알아야 한다는 것이다.

프로퍼티 파일의 경로를 알아오는 방법에 대해서 몇가지 생각해 보자

1. 프로그램 코드에 상수로 프로터피 파일의 경로를 둔다.

예를들면,

public staitc final String PATH = "/app/myapp/myprop.properties";

 

라고 두는 것이다. 뭐 이건 말 안해도 알겠지만 별로 좋지 않은 방법이다. 경로나 이름이 바뀌면 새로 컴파일 해야 하고, 뭐 이래저래 좋지 않은거 같다.

 

2. java 실행 옵션으로 세팅해서 프로그램에서 사용한다.

java 프로그램을 실행시킬 때 실행 옵션으로 프로퍼티 파일의 경로를 줘서 그 옵션값을 읽어서 경로로 사용하도록 하는 것이다.

 

String path = System.getProperty( "path" );

라는 형태로 사용하면 실행시 준 옵션값을 가져올 수 있다.

이 방법도 많이 사용하는 방법으로 나름대로 쓸만하다. 그렇지만 실행시 옵션을 설정한다는 것이 별로 마음에 안든다.

 

 

3. ClassLoader를 사용하여 가져온다.

혹시 이거 신기하게 생각해 본 사람이 있을지 모르겠는데, log4j를 사용하다 보면 log4j.properties라는 파일을 생성해 두면 내가 특별히 경로를 세팅하지 않았는데도 log4j가 알아서 log4j.properties를 읽어서 사용한다. 나는 처음에 이게 무지 신기했다. log4j가 어떻게 알고 그 위치의 log4j.properties를 읽어 들이는 걸까?

 

해답은 ClassLoader 였다.

 

classloader 주요 기능은 클래스를 로딩하는 것이다.(이름에서 알 수 있는 너무 당연한 이야긴가? ^^;)

 

하지만 기능이 한가지 더 있는데 바로 클래스 파일 뿐아니라 다른 리소스 파일도 읽어 주는 역할이다.

ClassLoader.getResource( String name )이 그 역할을 하는 메소드다(이 메소드 외에도 getResource... 메소드들이 몇가지 더 있다. 알아서 찾아 보시길...)

 

getResource는 클래스 패스내에서 해당 이름으로 된 파일을 찾아서 그 URL을 넘겨준다. 중요한 포인트는 바로 클래스 패스 내에 있는 파일이라는 것이다.

 

java를 실행시킬때 -classpath라고 주는 바로 그 클래스 패스 말이다. classpath에 설정한 클래스 패스내에 프로퍼티 파일을 두면 ClassLoader를 통해서 프로퍼티 파일을 가져올 수 있는 것이다. 별거 아닌 기능 같지만 쓰다보면 상당히 편리하다.

실제 구현 내용을 간단히 살펴보면 다음과 같다.

 

        ClassLoader cl;
        cl = Thread.currentThread().getContextClassLoader();
        if( cl == null )
            cl = ClassLoader.getSystemClassLoader();
               
        URL url = cl.getResource( "myprop.properties" );

 

위 내용은 log4j의 소스에서 일부 참조한 것이다.

위 소스를 참조해서 쉽게 프로퍼티 파일을 다룰 수 있는 클래스를 만들어 보는 것도 좋을 듯 하다.

앞선 글에서 ClassLoader를 이용하여 property 파일 찾는 코드에 대해 부연 설명을 좀 해 보자.

앞선 코드는

 

        ClassLoader cl;
        cl = Thread.currentThread().getContextClassLoader();
        if( cl == null )
            cl = ClassLoader.getSystemClassLoader();                
        URL url = cl.getResource( "myprop.properties" );

 

였다.

이때 그냥

 

ClassLoader cl = ClassLoader.getSystemClassLoader();

하지 않고

 

cl = Thread.getContextClassLoader();

를 통해서 먼저 ClassLoader를 구해오는 것은 나름대로 이유가 있다.

 

java 프로그래밍의 상당 부분은 독립실행되는 java application보다 web application의 형태로, container(tomcat, weblogic 등등) 안에서 실행되는 application으로 제작되는 경우가 많다.

 

container는 여러 application을 분리하기 위해 각 application마다 ClassLoader를 새로 생성해서 사용하며, application을 구동시키기 위해 Thread를 생성한다. 이때 container application을 위해 생성한 Thread setContextClassLoader를 통하여 그 application을 위해 생성한 ClassLoader를 세팅해 준다.

 

따라서 container안에서 실행되는 application에서는 resource를 찾기 위해 system ClassLoader가 아니라 그 application을 로드하는 ClassLoader를 사용해야 한다. 그래서 위의 코드처럼 Thread ClassLoader를 먼저 체크해 봐야 하는 것이다.

 

예상했겠지만, 이때 그 application을 위해 생성된 ClassLoader에 세팅되는 Class Path, application에만 해당되는 path( ex)classes, lib 등등)만 추가되기 때문에 다른 위치에 있는 resource는 가져오지 않는, 아니 가져올 수 없게 되는 것이다.

 

물론 독립실행형 java application에서는 그냥 System.getSystemClassLoader()만 사용해도 된다.

[출처] java에서 Property 파일 쉽게 찾기2|작성자 쫌조

 

Posted by 파이팅야
,