Learn business/Java

자바 클래스패스


이전부터 스프링으로 웹 서비스를 개발할 때 테스트 코드를 짜는 것에 대한 중요성은 일찍히 알고 있었다. 테스트 코드를 만들다 보면 항상 봉착하는 문제가 있었는데 내가 설정한 빈 파일 혹은 JSON과 같은 파일을 어떻게 찾아야 하는지였다. 이럴 땐 항상 이미 성공한 다른 코드를 복붙하기에 바빴다. 그러면서 클래스 패스가 무엇인지 정확하게 모른 채 넘어갔었는데 이번 기회에 부셔보자.

 

1. 클래스 패스(classpath)

클래스 패스는 쉽게 말해 JVM이 프로그램을 실행할 때 클래스를 찾기 위한 기준이 되는 경로라고 생각하면 간단하다. 만약 클래스 패스를 설정하지 않았다면 디폴트는 현재 경로를 바라보게 된다. 우리가 많이 사용하는 intellij IDE도 클래스 패스를 설정하지 않으면 기본적으로 현재 경로에서 파일을 찾는다. 말로만 이해하지 말고 직접 눈으로 확인해보자.

class WhatYourName {
        public static void main(String[] args) {
                AAA aaa = new AAA();
                aaa.showName();

                BBB bbb = new BBB();
                bbb.showName();
        }

}

class AAA {
        public void showName() {
                System.out.println("AAA");
        }
}

class BBB {
        public void showName() {
                System.out.println("BBB");
        }
}

위와 같이 WhatYourName.java 파일 하나에 3개의 클래스가 있다. 컴파일을하면 당연히 WhatYourName.class / AAA.class / BBB.class 총 3개의 클래스가 만들어진다는 것을 예측할 수 있다. 그리고 main() 메소드가 있는 WhatYourName.class 파일을 실행시키면 순차적으로 AAA와 BBB 콘솔에 찍힐 것이다.

WhatYourName.java 파일을 컴파일 한 후 그 결과물 사진
WhatYourName.class 파일 실행

당연한 결과라고 생각할 것이다. 그런데 work 디렉토리에 myclass라는 폴더를 만들어서 AAA.class와 BBB.class를 myclass 폴더 안에 넣으면 어떻게 될까? 당연히 클래스 패스를 따로 설정하지 않았으므로 NoClassDefFoundError 를 마주하게 될 것이다. 바로 아래 첨부한 이미지 처럼 말이다.

myclass에 AAA.class와 BBB.class를 이동시킴
AAA.class와 BBB.class를 이동 후 WhatYourName 파일을 실행시켜 봄

위 이미지를 통해서 우리는 클래스 패스를 설정하지 않고 디폴트로 설정해두면 현재 경로에서 선언된 클래스를 찾는다는 것을 알 수 있었다. 여기서 현재 경로란 WhatYourName.class 파일이 실행되고 있는 바로 그 경로를 말한다.

 

2. 클래스 패스 어떻게 확인하고 어떻게 설정하지?

클래스 패스는 아래 첨부한 이미지처럼  "echo $CLASSPATH"로 확인한다. 실제로 클래스 패스가 설정이 되어있지 않으면 빈칸이 나온다. 참고로 윈도우와 리눅스 환경에서 클래스 패스를 확인하는 방법은 다르다. 윈도우는 명령 프롬프트에서 "set classpath" 라고 치면 나온다.

CLASSPATH 경로 확인 - 설정된 CLASSPATH가 없는 경우

그럼 한번 클래스 패스를 설정해보자. 루트 디렉토리로 이동하여 숨김파일로 되어있는 .bash_profile을 vi로 수정해보자.

sudo vi .bash_profile
.bash_profile

뭐 .bash_profile에 여러가지 적혀있는 것이 많은데 나머지는 무시하고 classpath 변수를 선언해서 테스트하려고 하는 경로를 넣어주자. 나의 경우는 아래와 같이 넣어 주었다.

export CLASSPATH=$CLASSPATH:/Users/vvshinevv/work/myclass

.bash_profile에 classpath 추가

이렇게 설정을 함으로써 우리는 JVM에게 프로그램을 실행할 때 /Users/vvshinevv/work/myclass 에 있는 클래스 파일도 찾아달라고 말하는 것과 같다. 사실 위와 같이하는 방법은 클래스 패스를 고정하는 방법으로 그렇게 추천하는 방법은 아니다. 다만 클래스 패스가 무엇인지에 대해 눈으로 확인하기 위해서 위와 같은 방법을 채택하였으니 이해만 하고 넘어가자. 이렇게 설정을 하였으면 echo $CLASSPATH 명령어를 실행해 보자. 아까는 보이지 않았던 클래스 패스 경로가 보일 것이다. (만약 안되면 터미널을 종료 후 다시 실행해 보자.)

echo $CLASSPATH

 

3. 클래스 패스 추가하고 실행해 보기

이제 .bash_profile을 수정하였으니 터미널을 껐다가 다시 실행해보자. 그리고 예제 파일이 있는 디렉토리에 들어가서 실행을 시켜보면, 아래 첨부한 이미지와 같이 정상적으로 동작하는 것을 확인할 수 있다.

클래스 패스 추가 후 실행한 결과

 

4.Intellij 에서 실행해 확인하기

위에서도 말했듯이 Intellij에서도 역시 설정을 추가하지 않으면 현재 디렉토리를 바라보도록 되어있다. 보통 TC를 작성할 때 내가 빈으로 등록한 설정 파일(xml 혹은 java)을 어떻게 찾아야 할지 막막했었던 기억이 난다. 하지만 어렵게 생각할 필요가 없다. Intellij 에게 클래스 패스 파일 경로를 알려줬다면 그 경로를 입력하면 되고, 알려주지 않았다면 현재 디렉토리로부터 설정 파일이 있는 위치를 찾아 들어가면 된다.

 

File > Project Structure 경로로 이동하면 아래와 같은 팝업 창이 뜬다.

File > Project Structure

바로 Intellij에게 파일을 찾을 수 있도록 클래스 패스로 알려주는 화면이다. 특히 테스트 코드의 설정 파일이 들어있는 src/test/resourceTest Resource Folders라고 Intellij에게 알려주고 있다. 이렇게 되면 아래와 같이 ContextConfiguration을 설정해 줄 수 있다.

@ContextConfiguration(locations = "classpath:spring/applicationContext-test.xml")

즉, locations = "classpath:...." 여기까지가 /User/vvshinevv/toby-spring/src/test/resource를 의미하는 것이 된다. 그리고 실제로 클래스 패스를 제거한다면 아래와 같이 Intellij가 해당 파일을 찾을 수 없다고 빨간색 줄을 긋는다.

 

클래스 패스 제거
제거 후 Intellij에서 파일을 찾을 수 없어서 에러를 띄운다.

그럼 당장에 찾을 수 없으니 클래스 패스의 디폴트 경로가 현재 경로 즉 UserDaoJdbcTest 클래스와 같은 위치에 있으면 분명 찾을 수 있을 것이다. applicationContext-test.xml 파일을 같은 경로로 이동 시켜보았더니 아래와 같이 정상으로 파일의 위치를 찾는 모습이었다.

같은 경로에 있는 applicationContext-test.xml

이렇게 공부해보니 헷갈리기만 했던 클래스 패스도 별거 아니다. 다음부터 헷갈려서 정상적으로 돌아가는 파일을 찾아서 복붙하지 말고 이해하면서 코딩하자.

'Learn business > Java' 카테고리의 다른 글

Enum과 Generic 함께 사용하기  (0) 2020.05.17
[5편] 제네릭이란?  (3) 2020.01.05
[4편] 제네릭이란?  (1) 2020.01.05
[3편] 제네릭이란?  (1) 2019.11.02
[2편] 제네릭이란?  (0) 2019.11.02