스프링에서는 클래스패스를 이용해서 리소스를 가져오도록 설정하는 경우가 많다. 설정파일 처럼 애플리케이션의 일부인 경우에는 환경에 따라서 달라지는 파일시스템 패스보다 클래스패스를 사용해서 파일의 위치를 지정하는 것이 더 낫기 때문이다.

대표적인 예는 XML설정파일을 읽어서 초기화 하는 ClasspathXmlApplicationContext이다. 이름 그대로 클래스패스로 된 설정파일 위치를 파라미터로 받는다. 그렇다면 다음과 같은 코드에서 context.xml 파일의 위치는 어디일까?

new ClassPathXmlApplicationContext(“context.xml”)

이 때 context.xml은 /context.xml과 마찬가지이다. 다시 말해서 context.xml은 클래스패스 루트에 있어야 한다.

만약 서브패키지에 있는 파일이라면 다음과 같이 경로를 직접 적어줘야 한다.

new ClassPathXmlApplicationContext(“a/b/c/context.xml”)

보통은 클래스패스 루트에 설정파일을 두기 때문에 별 문제는 없지만, 테스트 등에서라면 특정 패키지 안에 있는 설정파일을 사용할 경우가 있는데 이 때 패키지를 일일이 지정해주는 것은 번거롭다. 이 때는 같은 클래스패스에 있는 클래스 정보를 넘겨주는 방법이 편리하다. 예를 들어 Hello 클래스가 a.b.c라는 패키지에 있다면 위의 설정은 다음과 같이 바꿀 수 있다.

new ClassPathXmlApplicationContext(“context.xml”, Hello.class)

Hello클래스의 클래스패스로부터 상대적인 위치를 찾는 것이다.

그런데 3.0에서 ClassPathXmlApplicationContext 대신 사용할 것을 권장하는 GenericXmlApplicationContext에는 이렇게 클래스 파라미터를 주는 방법이 없다. 그렇다면 항상 풀 클래스패스를 적어줘야 할까? 물론 그렇다.

하지만 스프링의 ClassUtil에서 제공하는 유틸리티 메소드를 사용하면 다음과 같이 작성할 수도 있다.

new GenericXmlApplicationContext(ClassUtils.classPackageAsResourcePath(clazz) + "/context.xml”);

classPackageAsResourcePath() 메소드는 클래스의 패키지를 클래패스 리소스 포맷으로 바꿔주는 메소드이다.

 

그런데 한가지 주의할 사항이 있다. 바로 테스트 컨텍스트 프레임워크를 사용할 경우이다.

스프링 테스트를 이용해서 다음과 같이 설정파일을 읽어서 동작하는 테스트 클래스를 작성했다고 해보자.

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("context.xml") 
public class MyTest {

이 때도 context.xml은 /context.xml과 마찬가지일까?

아니다. @ContextConfiguration은 독특하게도 /로 시작하지 않는 클래스패스는 테스트 클래스의 클래스 패스로부터 상대 위치로 인식한다. 클래스패스 루트에 있는 파일을 지정하려면 명시적으로 /context.xml이라고 적어야 한다. 테스트에서는 클래스별로 별도의 설정파일을 가져가는 경우가 만고, 이 때는 클래스와 같은 위치에 파일을 넣는 것이 편하기 때문에 이를 디폴트로 지정한 것 같다. 테스트 컨텍스트 프레임워크를 개발한 사람은 로드 존슨이나 유겐 횔러가 아닌, 새로운 개발자였기 때문일 수도 있고.

 

같은 클래스패스 파라미터을 받는 경우지만 이렇게 차이가 있다는 점에 주의하자. 두 가지 경우를 구분해서 사용하는 것이 귀찮으면 클래스패스 루트는 항상 /로 시작하는 습관을 들이는 것도 좋은 방법이다. API문서를 참고해서 메소드 파라미터가 어떻게 해석되는지 참고해보는 습관을 들이는 것도 좋을 것이다.


출처 - http://toby.epril.com/?p=1015




Posted by linuxism
,