Spring MVC

Spring의 classpath:의 경로 위치

GPLWorker 2020. 1. 2. 00:35

아래 Spring web.xml의 ContextLoaderListener의 환경설정 파일인 applicationContext.xml의 위치를 지정하는 코드에서 classpath:의 위치가 어디인가?

  <context-param>
  	<param-name>contextConfigLocation</param-name>
  	<param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  
  <listener>
  	<listener-class>
  		org.springframework.web.context.ContextLoaderListener
  	</listener-class>
  </listener>

만일 위 설정 내용에서 classpath:을 빼버리면 당연히 applicationContext.xml를 찾지 못한다는 에러가 발생한다. 아래와 같이

org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [applicationContext.xml]; nested exception is java.io.FileNotFoundException: class path resource [applicationContext.xml] cannot be opened because it does not exist

그렇다면 저 classpath:의 위치는 어디를 가리킨단 말인가? 만일 프로젝트 이름이 BordWebDay4Class04라고 한다면 
이클립스의 프로젝트명에서 마우스 우측 클릭 ⇒ Build Path ⇒ Configure Build Path... ⇒ 상단 4개의 탭 중에서 Source 탭 선택 하면 아래와 같은 내용이 보일 것이다.


여기서 classpath:의 위치가 2곳 나타나 있다.
BordWebDay4Class04/src/main/java/ 
BordWebDay4Class04/src/main/resources/ 

따라서 applicationContext.xml를 위 두 경로 중 어느 한곳에 위치시키면 정상적으로 구동이 된다.
그런데 BordWebDay4Class04/src/main/java에는 당연히 java 소스코드를, BordWebDay4Class04/src/main/resources에는 스프링 설정 파일을 위치시킨다. 
따라서 applicationContext.xml를 BordWebDay4Class04/src/main/resources/에 위치시키면 된다.

그런데 만일 applicationContext.xml가 BordWebDay4Class04/src/main/resources/joe/ 아래에 설정 파일이 있다면 역시 아래 에러가 발생할 것이다.

java.io.FileNotFoundException: class path resource [applicationContext.xml] cannot be opened because it does not exist

해결책은 몇 가지 방법이 있는데 아래 방법 중 어느 하나를 적용하면 된다.
(1) classpath:에 joe라는 경로를 포함시키는 방법

  <context-param>
  	<param-name>contextConfigLocation</param-name>
  	<param-value>classpath:/joe/applicationContext.xml</param-value>
  </context-param>

(2) applicationContext.xml가 있는 BordWebDay4Class04/src/main/resources/joe/를 classpath에 등록하는 방법
이클립스의 프로젝트명에서 마우스 우측 클릭 ⇒ Build Path ⇒ Configure Build Path... ⇒ 상단 4개의 탭 중에서 Source 탭 선택 ⇒ 우측 "Add folder..." 버튼 클릭하여 BordWebDay4Class04/src/main/resources/joe/ 경로를 추가해 준다.

(3) 와일드 카드(**)를 이용해서 현재 classpath 하위의 모든 디렉토리를 포함하도록 설정

  <context-param>
  	<param-name>contextConfigLocation</param-name>
  	<param-value>classpath:/**/applicationContext.xml</param-value>
  </context-param>


위와 같이 설정하면 아래의 경우들이 모두 정상적으로 동작한다.

BordWebDay4Class04/src/main/resources/joe/applicationContext.xml
BordWebDay4Class04/src/main/resources/joe/myjob/applicationContext.xml
BordWebDay4Class04/src/main/resources/joe/myjob/yourjob/applicationContext.xml
BordWebDay4Class04/src/main/resources/joe/myjob/herjob/applicationContext.xml
BordWebDay4Class04/src/main/resources/hisjob/applicationContext.xml

이 작업 후 Tomcat을 restart 하면 이제 정상적으로 구동이 될 것이다.

여기서 와일드카드가 하나일때인 /*/와 두개 일때인 /**/의 차이는

전자의 경우는(/*/의 경우는) 현재의 classpath: 디렉토리 하위에 있는 디렉토리들 중 첫번째 하위 디렉토리만 해당된다.
즉 applicationContext.xml가 classpath: 디렉토리 하위의 디렉토리들 중 어느 하위에 속해있든지 모두 인식이 된다는 뜻이다.

/joe/applicationContext.xml    (정상적으로 인식됨)
/kim/applicationContext.xml    (정상적으로 인식됨)
/kim/goo/applicationContext.xml   (인식 안됨)
/seo/qqq/applicationContext.xml   (인식 안됨)

후자의 경우는(/**/의 경우는) 현재의 classpath: 디렉토리 하위에 몇개의 하위 디렉토리들이 있어도 그 하위 모든 디렉토리들을 다 포함시킬수가 있다.
즉 applicationContext.xml가 classpath: 디렉토리 하위의 디렉토리들 중 어느 하위에 속해있든지 모두 인식이 된다는 뜻이다.

/joe/applicationContext.xml    (정상적으로 인식됨)
/kim/applicationContext.xml    (정상적으로 인식됨)
/kim/goo/applicationContext.xml   (정상적으로 인식됨)
/seo/qqq/applicationContext.xml   (정상적으로 인식됨)

아래는 Tomcat을 재구동했을 때 정상적으로 인식되었을 때의 로그이고

정보: Initializing Spring root WebApplicationContext
INFO : org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization started
INFO : org.springframework.web.context.support.XmlWebApplicationContext - Refreshing Root WebApplicationContext: startup date [Wed Jan 08 16:08:18 KST 2020]; root of context hierarchy

INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from file [D:\MyProgramStudy\Spring\.metadata\.plugins\org.eclipse.wst.server.core\tmp2\wtpwebapps\BordWebDay4Class03\WEB-INF\classes\joe\myjob\herjob\applicationContext.xml]
INFO : org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring

INFO : org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization completed in 1593 ms

아래는 Tomcat을 재구동했을 때 인식되지 못했을 때의 로그이다.

정보: Initializing Spring root WebApplicationContext
INFO : org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization started
INFO : org.springframework.web.context.support.XmlWebApplicationContext - Refreshing Root WebApplicationContext: startup date [Wed Jan 08 16:15:38 KST 2020]; root of context hierarchy

INFO : org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization completed in 357 ms