메이븐 기반 웹 프로젝트에서 이클립스의 Run on Server의 tomcat을 구동하면 자꾸 index.jsp 페이지에서 NullPointException이 발생한다.
index.jsp 페이지에는 “index” 라는 문자열만 딸랑 있는데 웬 Exception?
서블릿관련 jar 파일때문에 꼬였나?
문제 추적 start~
1. pom.xml 확인
pom.xml을 확인해 보면 다음과 같이 되어 있다.
scope는 provided로 되어 있으니 프로젝트 컴파일 시에만 사용하고, 배포할 때에는 제외되게 설정하였으니 문제없다.
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
2. build path 확인
Java Build Path > Libraries 에도 maven dependency 설정이 잘 되어 있다.
물론 이곳에 설정이 잘 되어 있다는 얘기는 의존성 라이브러리들이 추가되어 있어서 java 컴파일 시 에러가 없다는 말이다.
3. Deployment Assembly 확인
이클립스의 Deployment Assembly 메뉴에 들어가 봤다.
음.. 뭔가 이상하다.
maven dependency library가 추가 되어 있네. (추가된 이유는 WAS를 기동할 때 maven dependency library에 존재하는 클래스들을 찾을 수 없다는 ClassNotFoundException이 발생해서 추가 하였음)
이곳에 라이브러리가 추가 되어 있으면 D:\dev\workspace\project\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\IncrossSpring\WEB-INF\lib 경로에 maven dependency에 정의되어 있는 jar 파일들이 모두 들어가 버린다.
.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\ 디렉토리는 이클립스에서 Run on Server를 이용하여 WAS를 구동할 때 프로젝트 소스를 copy해 놓는 곳이다. (소스 조립 디렉토리로 생각하면 될 듯)
이클립스에서 이와 같이 별도의 디렉토리에 소스를 copy한 후 WAS를 띄우는 이유는 웹 프로젝트 구성 시 여러 개의 프로젝트로 구성하기 때문이다.
문제는 Deployment Assembly에 maven dependency가 설정되어 있으면 pom.xml 에 정의한 scope에 상관 없이 servlet-api.jar, jsp-api.jar 파일도 이곳에 추가 된다는 것이다.
scope에 따른 설정 전략은 maven goal을 이용할 때에만 적용된다는 것을 이번 문제를 통해서 알게 되었다.
이런 현상으로 인해 웹 어플리케이션이 구동되면서 ${TOMCAT_HOME}/lib 에 있는 서블릿 관련 jar 파일과 maven pom.xml에 정의되어 있는 서블릿 jar 파일이 충돌하게 된 것이다.
4. 해결 방법은?
그럼 위와 같은 현상을 없애기 위해서는 어떻게 해야 하나?
Deployment Assembly에서 maven dependency를 삭제하고, maven goal에 다음을 입력 후 실행하자.
war:inplace
빌드가 완료되면 \src\main\webapp\WEB-INF\lib 경로에 maven dependency 라이브러리들이 추가된다.
배포 시 pom.xml에 정의된 scope가 적용되고 서블릿 관련 jar파일은 추가되지 않는다.
5. 결론
결론은 이클립스에서 Run on Server를 이용하여 tomcat을 구동하기 위해서는 WEB-INF/lib에 jar 파일이 추가되어야 하고, maven project에서 lib 경로에 라이브러리들을 추가하기 위해서는 war:inplace goal을 이용하면 된다.