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로 변경 하게 되었구나. 하고 혼자만의 이유로 막 수긍한 날 이었습니다.
'java' 카테고리의 다른 글
restTemplate large file download stream (0) | 2018.09.03 |
---|---|
java - pretty log - 예쁜 로그를 남기자! (0) | 2018.08.30 |
java php aes ecb nopadding (2) | 2018.08.29 |
enum fasterxml jackson Serializing and DeSerializer (0) | 2018.08.24 |
Spring RestTemplate Request Parameter Encoding (0) | 2018.08.16 |
spring boot main args - ApplicationArguments (0) | 2018.08.16 |
java file create time (0) | 2018.08.13 |
org.apache.ibatis.type.TypeException: Could not resolve type alias (4) | 2018.08.09 |