반응형

tomcat connection pool 사용 삽질기를 공유합니다. 

보통은 아래 tomcat-jdbc의 scope를 provided 로 해서 로컬 개발환경에서만 쓰고 운영할 환경이 Tomcat 이라면 별도로 라이브러리를 추가할 필요가 없습니다.

1
2
3
4
5
    <!-- tomcat-jdbc -->
    <dependency>
      <groupId>org.apache.tomcat</groupId>
      <artifactId>tomcat-jdbc</artifactId>
    </dependency>


이녀석은 tomcat-jdbc에 의존성이 걸려있는 라이브러리 입니다.

1
2
3
4
5
6
    <dependency>
      <groupId>org.apache.tomcat</groupId>
      <artifactId>tomcat-juli</artifactId>
      <version>8.5.6</version>
      <scope>compile</scope>
    </dependency>


그런데 이번에 운영환경이 Jeus인 곳에서 부가적으로 tomcat-jdbc를 같이 써보려고 시도했다가 고생좀 했습니다.

로컬 개발환경에서는 잘 돌아가던 녀석이 운영환경에 배포했더니 아래와 같은 처음 보는 오류를 발생시켰습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.IncompatibleClassChangeError: Found class org.apache.juli.logging.Log, but interface was expected
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:978)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:734)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
 
        ...
 
Caused by: java.lang.IncompatibleClassChangeError: Found class org.apache.juli.logging.Log, but interface was expected
        at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:264)
        at org.apache.tomcat.jdbc.pool.PooledConnection.connect(PooledConnection.java:203)
        at org.apache.tomcat.jdbc.pool.ConnectionPool.createConnection(ConnectionPool.java:718)
        at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:650)
        at org.apache.tomcat.jdbc.pool.ConnectionPool.init(ConnectionPool.java:468)
        at org.apache.tomcat.jdbc.pool.ConnectionPool.<init>(ConnectionPool.java:143)
        at org.apache.tomcat.jdbc.pool.DataSourceProxy.pCreatePool(DataSourceProxy.java:118)
        at org.apache.tomcat.jdbc.pool.DataSourceProxy.createPool(DataSourceProxy.java:107)
        at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:131)
        at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111)
        at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77)
        at org.mybatis.spring.transaction.SpringManagedTransaction.openConnection(SpringManagedTransaction.java:82)
        at org.mybatis.spring.transaction.SpringManagedTransaction.getConnection(SpringManagedTransaction.java:68)


오류 내용인즉슨 org.apache.juli.logging.Log 클래스를 찾았는데 인터페이스만 있고 구현체가 없다는 내용인걸로 보입니다.

위 오류 로그의 13Line에 보면 PooledConnection.java:264 여기가 오류 발생원인 마지막 출처이죠. 


그래서 해당 소스를 찾아보았더니 PooledConnection.java:264 에 해당하는 Line이 아래 소스의 12Line 입니다.

 if (log.isDebugEnabled()) {  이 부분 입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;    
 
public class PooledConnection {
 
...
 
    protected void connectUsingDriver() throws SQLException {
 
        try {
            if (driver==null) {
                if (log.isDebugEnabled()) {
                    log.debug("Instantiating driver using class: "+poolProperties.getDriverClassName()+" [url="+poolProperties.getUrl()+"]");
                }
                ...


그래서 org.apache.juli.logging.Log 를 찾아가 보았더니 그냥 Interface 이더군요. 

위의 maven dependency 에 tomcat-jdbc 나 그에 속해있는 tomcat-juli에는 해당 인터페이스의 구현체가 전혀 없더군요. OTL


tomcat-jdbc 혼자서 사용할 수 없는 거라면 tomcat-juli 처럼 필요한 dependency를 걸어 놓아야 하는거 아닙니까?

(뭐 Debug Level 안 돌리면 문제가 없을지는 모르겠지만)


그래서 구현체가 어디있는지 찾아보았더니 tomcat-embed-core에 있더군요. 

로그 구현체는 core 에 있고 인터페이스는 jdbc에 있고 이거 뭔가 좀 바뀐것 같지 않나요?

1
2
3
4
5
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-core</artifactId>
        <scope>provided</scope>
    </dependency


이건 tomcat-embed-core에 있는 구현체 입니다.

1
2
3
4
5
6
package org.apache.juli.logging;
 
/**
 * Hardcoded java.util.logging commons-logging implementation.
 */
class DirectJDKLog implements Log {        



이러한 뭔가 앞뒤 안맞는 tomcat-jdbc 를 보고 심하게 짜증이 일어나서 tomcat-jdbc 를 버리고 Hikari 로 갈아타 버렸습니다.

그래서 SpringBoot 2.0 부터는Default CP를 tomcat-jdbc에서 Hikari로 변경 하게 되었구나. 하고 혼자만의 이유로 막 수긍한 날 이었습니다.

반응형

+ Recent posts