본문 바로가기

프로그래밍/Spring

Maven에서 Tomcat을 실행시켜 결과를 확인해보자..

기존에 Maven을 이용해서 Spring MVC를 개발할때는 어떤식으로는 WAS가 자신의 컴퓨터에 설치되어 있어야 했다. Tomcat이든 JBoss든..아마 대부분 Tomcat을 설치해서 하겠지만.. 근데 Eclipse에서 Tomcat 기반으로 개발할땐 불편한점이 몇몇 있었다. 프로젝트 설정에서 Deployment Assembly의 속성을 건드려줘야 하고 또 pom.xml에서 dependency 태그에 있는 javax.servlet.servlet-api와 javax.servlet.jsp-api를 주석처리를 했다가 다시 war로 배포할때는 주석처리한것을 지워야 했다(scope를 provided로 해도 tomcat 기동시 오류 발생..)

 

그래서 이런 불편한 점을 없애볼려고 시도한것이 Jetty를 이용해서 빌드시 war로 빌드하는게 아니라 내부적으로 jetty가 떠서 거기서 내가 만든 플젝이 deploy되는 방법이었다. 즉 Maven Build를 하면 Embedded Jetty가 구동이 되고 그 Jetty안에 현재 내가 작업한 Project가 deploy 되는 것이었다. 이 방법이 가능해지면 자신의 컴에 WAS를 설치하지 않아도 개발이 가능해지는것이었다. 

 

그래서 현재 들어가 있는 프로젝트에서는 이 방법을 이용해서 개발을 진행했다. 나랑 같은 방법으로 진행했던 개발자도 있었고 아니면 기존에 하던 스타일로 Tomcat 설치한후 Eclipse에 Tomcat 등록해서 개발하는 개발자도 있었다. 그러다가 프로젝트 끝무렵에 구글링을 하다보니 Tomcat도 이런 기능을 해주는 Maven Plug In이 생겼다고 해서 하루 정도 삽질끝에 이걸 설정할수 있게 되었다(삽질 하게 된 이유에 대해서는 나중에 따로 얘기해주겠다)

 

관련 설정을 설명하기 전에 내가 설정하고자 하는 내용을 먼저 설명하고자 하자면 단순하다. Tomcat을 구동하는데 Tomcat에서 Connection Pool을 만들고 JNDI를 이용해서 Spring MVC에서 접근해서 Database Connection을 가져오는 것이다. 그러면 이 기능을 할려면 어떻게 해야 하느냐..우리가 Maven을 이용해서 Maven Web Project를 만들면 src/main/webapp/META-INF 디렉토리가 있다. 여기에 context.xml을 다음과 같이 만들어 넣는다

 

<?xml version='1.0' encoding='utf-8'?>
<Context antiJARLocking="true" antiResourceLocking="true">
	<WatchedResource>WEB-INF/web.xml</WatchedResource>
	<!-- Connection Pool 설정 -->
	<Resource 
		name="jdbc/mytest"
		auth="Container" 
		type="javax.sql.DataSource" 
		factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
		maxActive="10" 
		minIdle="5" 
		maxWait="10000" 
		initialSize="5" 
		validationQuery="SELECT 1 FROM DUAL" 
		driverClassName="oracle.jdbc.driver.OracleDriver" 
		defaultAutoCommit="false"
		username="abcd" 
		password="efgh" 
		url="jdbc:oracle:thin:@192.168.10.20:1521:orcl"/>
</Context>

 

이번에 작업하면서 알게 되었는데..Tomcat 7.X로 올라가면서 기존에 Database Connection Pool을 만들때 사용하던 Apache Common DBCP를 버렸다고 한다. 그러면서 Apache DBCP가 아닌 자체 제작(?) 한 것을 사용한다고 한다(tomcat-jdbc.jar). 그러다보니 factory 속성에 사용되는 클래스가 org.apache.tomcat.jdbc.pool.DataSourceFactory로 바뀌게 되었다. 지금 예시로 들은 프로젝트는 Connection Pool을 여기서만 사용할려고 context.xml에 <Resource> 태그를 사용했으나 server.xml에 등록되는 Globaal Database Connection Pool을 사용한다면 <Resource> 태그가 아닌 <ResourceLink> 태그를 써서 server.xml에 등록된 Database Connection Pool을 이용해야 할 것이다.

 

그리고 web.xml에 다음과 같은 내용을 넣는다

 

<resource-ref>
	<description>jdbc/mytest</description>
	<res-ref-name>jdbc/mytest</res-ref-name>
	<res-type>javax.sql.DataSource</res-type>
	<res-auth>Container</res-auth>
</resource-ref>

 

지금까지는 별 내용이 없었다. 왜냐면 지금까지는 일반적으로 하는 Tomcat Setting과 다른게 전혀 없기때문이다. 여기까지의 설명에서 핵심은 src/main/webapp/META-INF 디렉토리에 context.xml이 있어야 한다는거 정도다. 그럼 지금부터 pom.xml의 셋팅을 보여주겠다. 전체 pom.xml의 내용은 다음과 같다. 오해할까봐 미리 적어두지만 지금 보여주는대로 그대로 Copy & Paste 하면 안된다. 각자 환경에 맞춰서 수정해야 한다. 전체소스를 보여주는 것은 앞뒤 관계 구조를 보여주기 위함일뿐이다.

 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.terry</groupId>
  <artifactId>testjob</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>jenkins</name>
  <description>TestJob</description>
  <properties>
    <java-version>1.6</java-version>
    <org.springframework-version>3.2.3.RELEASE</org.springframework-version>
    <org.slf4j-version>1.7.5</org.slf4j-version>
    <jackson-asl.version>1.9.13</jackson-asl.version>
    <tomcat.version>7.0.27</tomcat.version>
  </properties>
  <repositories>
    <repository>  
          <id>com.springsource.repository.bundles.release</id>  
          <name>SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases</name>
          <url>http://repository.springsource.com/maven/bundles/release</url> 
     </repository> 
     <repository>  
          <id>com.springsource.repository.bundles.external</id>  
          <name>SpringSource Enterprise Bundle Repository - External Bundle Releases</name>
          <url>http://repository.springsource.com/maven/bundles/external</url> 
     </repository>

     <repository> 
          <id>com.springsource.repository.libraries.release</id> 
          <name>SpringSource Enterprise Bundle Repository - SpringSource Library Releases</name> 
          <url>http://repository.springsource.com/maven/libraries/release</url> 
     </repository> 
     <repository> 
          <id>com.springsource.repository.libraries.external</id> 
          <name>SpringSource Enterprise Bundle Repository - External Library Releases</name> 
          <url>http://repository.springsource.com/maven/libraries/external</url> 
     </repository>   
  </repositories>
  
  <pluginRepositories>
    <pluginRepository>
      <id>apache.snapshots</id>
      <name>Apache Snapshots</name>
      <url>https://repository.apache.org/content/repositories/snapshots</url>
      <releases>
        <enabled>false</enabled>
      </releases>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
    </pluginRepository>
    <pluginRepository>
         <id>myNexus</id>
         <url>http://192.168.10.19:8080/nexus/content/groups/myNexus</url>
         <releases>
             <enabled>true</enabled>
         </releases>
         <snapshots>
             <enabled>true</enabled>
         </snapshots>
     </pluginRepository>
  </pluginRepositories>
  
  <dependencies>
  	<!-- Spring -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${org.springframework-version}</version>
        <exclusions>
            <exclusion>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>
 
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>
    
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-oxm</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>
    
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>
  
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.1.1</version>
    </dependency>
    
    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-core-asl</artifactId>
        <version>${jackson-asl.version}</version>
    </dependency>

    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>${jackson-asl.version}</version>
    </dependency>
    
    <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>
    
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
        <scope>provided</scope>
    </dependency>
    
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>${org.slf4j-version}</version>
        <scope>runtime</scope>
    </dependency>
    
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${org.slf4j-version}</version>
        <scope>runtime</scope>
    </dependency>
    
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>${org.slf4j-version}</version>
    </dependency>
    
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.16</version>
        <exclusions>
            <exclusion>
                <groupId>javax.mail</groupId>
                <artifactId>mail</artifactId>
            </exclusion>
            <exclusion>
                <groupId>javax.jms</groupId>
                <artifactId>jms</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.sun.jdmk</groupId>
                <artifactId>jmxtools</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.sun.jmx</groupId>
                <artifactId>jmxri</artifactId>
            </exclusion>
        </exclusions>
        <scope>runtime</scope>
    </dependency>
        
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>1.3.1</version>
    </dependency>
	
    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>com.springsource.javax.validation</artifactId>
        <version>1.0.0.GA</version>
    </dependency>
    
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>com.springsource.org.hibernate.validator</artifactId>
        <version>4.2.0.Final</version>
    </dependency>
    
    <dependency>
        <groupId>org.lazyluke</groupId>
        <artifactId>log4jdbc-remix</artifactId>
        <version>0.2.7</version>
    </dependency>
  </dependencies>

  <build>
  	<finalName>testjob</finalName>
    	<plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            <plugin>
            	<groupId>org.apache.maven.plugins</groupId>
            	<artifactId>maven-war-plugin</artifactId>
            	<configuration>
                	<warName>jenkins</warName>
            	</configuration>
        	</plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>org.test.int1.Main</mainClass>
                </configuration>
            </plugin>
            <plugin>
            	<groupId>org.apache.tomcat.maven</groupId>
            	<artifactId>tomcat7-maven-plugin</artifactId>
            	<version>2.2</version>
            	<configuration>
            		<port>8080</port>
            		<path>/mytest</path>
            		<contextFile>src/main/webapp/META-INF/context.xml</contextFile>
            		<contextReloadable>false</contextReloadable>
            	</configuration>
            	<dependencies>
            		<dependency>
        				<groupId>com.oracle</groupId>
        				<artifactId>ojdbc14</artifactId>
    					<version>10.2.0.5</version>
    				</dependency>
            	</dependencies>
        	</plugin>
        </plugins>
    </build>
</project>

 

여기서 눈여겨 봐야 할 부분이 2군데가 있다. 먼저 이 부분..

 

<pluginRepositories>
    <pluginRepository>
      <id>apache.snapshots</id>
      <name>Apache Snapshots</name>
      <url>https://repository.apache.org/content/repositories/snapshots</url>
      <releases>
        <enabled>false</enabled>
      </releases>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
    </pluginRepository>
    <pluginRepository>
         <id>myNexus</id>
         <url>http://192.168.10.19:8080/nexus/content/groups/myNexus</url>
         <releases>
             <enabled>true</enabled>
         </releases>
         <snapshots>
             <enabled>true</enabled>
         </snapshots>
     </pluginRepository>
</pluginRepositories>

 

<pluginRepositories> 태그는 <plugin>태그에서 명시된 maven plug in을 받아야 하는 Repository를 지정한다. 여기까지는 별 내용이 없다. Maven 사이트 가면 설명이 있으니까..근데 여기에다가 내가 사용하는 Nexus 사이트를 등록해두었다. 왜 이걸 등록해두었는지에 대해 설명하겠다. 위의 설정을 유심히 보았다면 지금 만드는 Tomcat Database Connection Pool은 Oracle과 연결되는 Connection Pool이다. 그러면 Oracle JDBC 드라이버가 필요할 것이다. 그러나 이 JDBC 드라이버의 <dependency> 설정을 <dependencies> 태그에 넣지 않았다. 무슨 의미냐면 Tomcat이 구동 될때 이 시점에서 Oracle Connection Pool을 만들것이고 이때 Oracle JDBC 드라이버가 사용되게 된다. 그러고 난 뒤에 우리가 만든 Web Application이 로딩된다. 그래서 Oracle JDBC 드라이버 jar 파일이 우리가 만든 Web Application에 들어가야 하는게 아니라 Tomcat이 로딩될때 사용될수 있도록 셋팅해줘야 한다. Tomcat이 설치된 디렉토리의 lib 디렉토리에 Oracle JDBC 드라이버를 넣어 Tomcat에서 제공하는 Datbase Connection Pool 설정법을 생각해보면 이해하기 쉬울것이다. 그래서 Oracle Jdbc 드라이버를 plug-in이 사용하도록 해야 하기 땜에 Oracle JDBC 드라이버가 있는 nexus를 <pluginRepository> 태그를 이용해서 플러그인이 이용하는 jar 파일로 한 것이다. 이것에 대한 구체적인 설정이 다음에 설명하는 부분에서 보일 것이다.

 

다음으로 설명할 내용은 Tomcat Plugin이다. 

 

<plugin>
      	<groupId>org.apache.tomcat.maven</groupId>
      	<artifactId>tomcat7-maven-plugin</artifactId>
       	<version>2.2</version>
       	<configuration>
       		<port>8080</port>
       		<path>/mytest</path>
       		<contextFile>src/main/webapp/META-INF/context.xml</contextFile>
       		<contextReloadable>false</contextReloadable>
       	</configuration>
       	<dependencies>
      		<dependency>
			<groupId>com.oracle</groupId>
			<artifactId>ojdbc14</artifactId>
			<version>10.2.0.5</version>
		</dependency>
       	</dependencies>
</plugin>

 

<configuration> 태그를 보면 많이 익숙한 속성들이 보인다. <port>는 Maven으로 Tomcat 로딩될때 사용할 포트번호, <path>는 context path, <contextFile>은 위에서 언급했던 context.xml이 있는 위치, <contextReloadable>은 클래스나 jsp 페이지 변경시 reload 할것인지의 여부다. 기타 다른 속성값들의 정의는 http://tomcat.apache.org/maven-plugin-2.0/tomcat7-maven-plugin/plugin-info.html에 가서 각 goal 별로 들어가서 확인해보면 된다(지금 이 작업과 관련해서는 goal이 tomcat7:run 인 것을 클릭해서 들어가면 알 수 있다)

 

여기에서 <dependencies> 태그가 있고 그 안에 Oracle JDBC 드라이버를 지정한 <dependency> 태그 설정이 있다. 이 부분이 <pluginRepositories> 태그 설명할때 장황하게 얘기했던 부분이다. Tomcat이 로딩되면서 사용할 jar 파일에 대한 dependency를 여기에서 설정해주면 된다. 만약 java mail 라이브러리를 써야 한다면 java mail 라이브러리에 대한 dependency 태그를 추가하면 된다.

 

이제 마지막으로 Eclipse에서 Maven Build 설정을 보여주고자 한다. 다음의 그림과 같이 설정하면 된다.

 

 

 

붉은색 사각형 박스 친것을 주목하자. clean을 통해 기존 컴파일 된 것을 깔끔하게 지우고 tomcat7:run을 하면 빌드를 한 후에 Maven 상에서 Embedded Tomcat을 띄우면서 자신이 작업한 Web Application을 Deploy 할 것이다.

 

이제 삽질을 했던 이유에 대해 설명하고 이 글을 마무리 하고자 한다. Oracle JDBC 드라이버가 연결이 되질 않길래 확인을 해보면 설정값 자체는 문제가 없었다. 문제는 태그명이었다. <contextFile> 태그를 <contextfile> 이렇게 전부 소문자로 한 것이 문제였다. 그래서 context.xml을 인식하지 못했던 것이다. 이거 자체를 발견하는데 시간이 걸렸던 것이 spring 태그의 경우 spring에서 지정한 태그가 아닌 경우 빨갛게 밑줄을 쳐주며 알려주는데 이 <contextfile>은 존재하지 않는 태그인데도 알려주질 않았었다. 그래서 외형적으로는 오류가 보이질 않아서 태그명을 잘못썼다..라는 것을 바로 알기가 어려웠었다. 이 내용을 보고 작업을 하시는 분이 있으시다면 태그명에 대해 하나하나 대소문자 잘 챙겨가며 하시길 바란다(아니면 여기에 써 놓은 태그를 복사해서 붙여넣기 하신뒤에 값만 바꿔치기 하셔도 된다)

 

※ 방금 위에 복사해서 붙여넣기..란 문구가 있어서 추가 설명을 드린다. 내 블로그에 적어놓은 글에 대해서는 복사 기능이 막혀있어서 간혹 질문을 하시는 분들을 보게 되는데..크롬에서 개발자도구를 이용하면 복사해서 붙여넣을수 있다. 단 좀 거추장스럽긴 하다. 이점 양해 부탁드린다