Embedded Tomcat에서 Spring WebApplicationInitializer 호출하는 방법

2015-02-13 12:29

프로젝트를 진행하다가 막히는 부분이 있어서 질문을 올립니다. 제목처럼 Embedded Tomcat 환경에서 Spring WebApplicationInitializer를 호출하는 방법을 찾습니다. 조언을 부탁드립니다!!

요약

  1. 기존의 프로젝트는 Embedded tomcat을 사용하는 XML기반의 Spring 웹서버이다.
  2. web.xml을 사용하지 않는 Spring WebApplicationInitializer 방식으로 리팩토링했다.
  3. WTP에서는 정상작동하나, embedded tomcat에서는 WebApplicationInitializer 구현클래스를 찾지 못한다.
  4. 구현클래스를 강제실행해보고자 했지만 embedded tomcat 소스에서 ServletContext를 만들지 못하고 있다.

설명

기존에 XML기반의 Spring 프로젝트를 Annotation 기반으로 바꾸면서, 기왕하는김에 web.xml도 없애보고 싶어서 Spring의 WebApplicationInitializer를 써보기로 했습니다.

기존에 사용하던 코드는 embedded tomcat을 사용했는데 (http://www.slipp.net/wiki/pages/viewpage.action?pageId=16711743 참조)

WebApplicationInitializer 방식으로 변경한 뒤에는 Eclipse WTP에서는 잘 동작하나, embedded tomcat에서는 어떻게 해야할지 모르겠더군요.

Embedded tomcat의 코드를 보면 기존에는 web.xml을 읽도록 addWebApp메서드를 실행하는데,

지금은 web.xml이 없으니, 실행하면 아래와 같이 로그가 출력됩니다.
WebApplicationInitializer를 클래스패스에서 찾기는 하는거 같은데, 제가 만든 코드를 인식하지 못합니다.


정보: No Spring WebApplicationInitializer types detected on classpath```

구글링을 조금 해보니, WebApplicationInitializer를 상속한 프로젝트 클래스의 onStartup method 강제실행 하는 경우가 있더군요. (실제 스프링의 컨테이너를 생성,설정하는 코드가 존재. Spring Container의 진입점)

위의 방식으로 구성해보고자 프로젝트 컴파일 클래스 중, WebApplicationInitializer Interface를 상속한 클래스를 찾고, reflection으로 onStartup(SevletContext context)를 실행하려고 해도, 인자로 전달해 줄 ServletContext를 어떻게 만들어야할지 모르겠네요.

//1번
Context context = tomcat.addWebapp("/", new File(webappDirLocation).getAbsolutePath());


//2번
Context context = tomcat.addContext("/", new File(webappDirLocation).getAbsolutePath());

위의 방법대로 context객체를 만들고, context.getServletContext()를 전달하면 아래와 같은 에러가 나는데,

Caused by: java.lang.IllegalStateException: Servlets can not be added to context / as the context has been initialised
	at org.apache.catalina.core.ApplicationContext.addServlet(ApplicationContext.java:1089)
	at org.apache.catalina.core.ApplicationContext.addServlet(ApplicationContext.java:1058)
	at org.apache.catalina.core.ApplicationContextFacade.addServlet(ApplicationContextFacade.java:521)
	at gaongil.config.WebConfiguration.onStartup(WebConfiguration.java:25)
	... 6 more

제가 시도한 방식이 아닌, EventListener방식이 존재하지 않을까 싶은데 찾지못하겠네요. 혹시 비슷한 경험이 있으시다면, 조언을 부탁드립니다!

5개의 의견 from SLiPP

2015-02-13 15:51

IDE(eclipse 또는 intellij)에서 컴파일 output 경로를 WEB-INF/classes 아래로 지정해 보면 좋겠다. 기본으로 이 디렉토리 아래의 클래스를 로딩하도록 되어 있다. 메이븐의 target/classses 경로를 인식하지 못하는 문제가 있다.

만약 경로를 변경하지 않고 사용하려면 http://slipp.net/questions/302 글이 참고가 될 수도 있겠다. 나도 테스트 해보지 않았는데 테스트해보고 잘 되면 결과 공유해주라.

2015-02-15 23:18

@자바지기 아..!! 공유해주신 링크대로 하니, 정상작동됩니다! 한참을 찾았는데 덕분에 잘 해결했어요. 정말 감사합니다!!

WTP에서의 배포경로 설정은

여기에서 설정하는 것 같은데, 맞을까요??

2015-02-16 10:11

@한석봉 WTP 설정을 굳이 eclipse에서 별도의 과정을 통해 진행할 필요는 없다.

maven과 같은 빌드 도구를 사용하면 WTP 관련된 설정이 자동화 될거다. 가능한 자동화하려고 노력해 보면 좋겠다.

    <build>
        <finalName>qna</finalName>


        <outputDirectory>webapp/WEB-INF/classes</outputDirectory>


        <plugins>
            [...]


            <plugin>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <downloadSources>true</downloadSources>
                    <wtpversion>2.0</wtpversion>
                    <wtpContextName>/</wtpContextName>
                </configuration>
            </plugin>
        </plugins>
    </build>

위 정도로 설정하면 되지 않을까? 그런데 embedded tomcat을 사용하고 있는데 WTP 설정을 하는 이유가 궁금해 지네. embedded tomcat 사용하면 굳이 WTP 관련 설정은 고려하지 않아도 될 듯 한데.

2015-02-16 10:34

@자바지기

아.. outputDirectory도 지정이 가능하군요. 다음부터는 maven에서 설정이 가능한지를 먼저 찾아봐야겠네요! embedded tomcat을 사용하면 문제없지만, 궁금해서 여쭤봤어요. 감사합니다 ^^

2015-06-27 18:56

통합테스트 환경 구축을 위해 3일동안 찾아보고, 해결한 내용을 공유합니다. 어찌된게 제 문제상황을 해결하기 위해 검색을 하는데 계속 slipp에 올린 이 글이 검색되어, 해결내용을 이곳에 작성합니다.

개발환경

  • 개발도구는 intelliJ 를 사용
  • embedded tomcat 8 이용
  • servlet-api 3.1 버전 사용
  • web.xml이 없는 Spring의 WebApplicationInitializer 방식으로 설정

문제상황

  • Rest API 서버 통합테스트를 위해 서버기동이 반드시 필요.
  • bash script(intergration.sh)에서 maven 명령어 실행(mvn clean install exec:java -Pid)
  • maven에서는 embedded tomcat8 서버를 실행하는 자바파일 호출.
  • 서버기동 과정에서 ClassNotFoundException 발생 (org.apache.jasper.servlet.JspServlet) at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1305)
    • IDE에서 Java Application 실행으로 동작할때는 정상적으로 작동
    • script를 통해 외부에서 실행할때만 에러가 발생

문제해결

  • ClassPath에 대한 문제인줄 알았지만, tomcat의 실행과정에서 Java Class 실행에서 사용하는 classLoader와 tomcat에서 사용하는 classLoader간의 불일치로 발생한 문제.
  • tomcat서버 실행시 둘간의 classLoader를 일치시키도록 아래의 코드를 추가하면 해결된다.
tomcat.getEngine().setParentClassLoader(this.getClass().getClassLoader());

참고레퍼런스

  • https://www.mulesoft.com/tcat/tomcat-classpath
  • https://tomcat.apache.org/tomcat-7.0-doc/config/jar-scanner.html
  • http://stefan-isele.logdown.com/posts/201646
의견 추가하기

연관태그

← 목록으로