Получение источника данных - закрытая ошибка при использовании весенней загрузки 1.2.7 в Tomcat 8 Java 8

У меня есть служба весенней загрузки, использующая Spring-Boot 1.2.7 при развертывании на Tomcat 8 с использованием Java 8. Служба работает нормально при новой перезагрузке сервера Tomcat, но после отмены и повторного развертывания я получаю сообщение об ошибке "Источник данных закрыт".

ОБНОВЛЕНИЕ это работает на tomcat 7 java 7. Привет всем, я создал простой пример приложения, которое получает ошибку и использует источник данных H2 jndi здесь. https://github.com/dstrimble/ws_preRatesFilter Я разместил файлы конфигурации tomcat в директории проекта.

Я использую источник данных JNDI на внешнем сервисе Tomcat, а не на встроенном.

sql.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">

    <util:properties id="preRatesFilterQueriesBean">
        <prop key="GET_SPECIFIC_FILTER_DATA">
            <![CDATA[
                SELECT ...
            ]]>
        </prop>

        <prop key="GET_ALL_FILTER_DATA">
            <![CDATA[
                SELECT ...
            ]]>
        </prop>
    </util:properties>
</beans>

WsPreRatesFilterApplication.java

@ImportResource({"classpath:sql.xml"})
public class WsPreRatesFilterApplication extends SpringBootServletInitializer {

    private final Logger logger = LoggerFactory.getLogger(WsPreRatesFilterApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(WsPreRatesFilterApplication.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        logger.info("Inside SpringApplicationBuilder configure");
        return application.sources(WsPreRatesFilterApplication.class);
    }
}

application.properties

spring.datasource.jndi-name=com.datasource.JBHDB2P
server.context-path=/ws_preRatesFilter
info.app.name=ws_preRatesFilter
info.app.description=Simple Boot Data Service
info.app.version=1.0.0

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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</groupId>
    <artifactId>ws_preRatesFilter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>ws_preRatesFilter</name>
    <description>filter rate input before rates called</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.7.RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <start-class>com.ws.preratesfilter.WsPreRatesFilterApplication</start-class>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

Ошибка:

{
  "timestamp": 1445347159226,
  "status": 500,
  "error": "Internal Server Error",
  "exception": "org.springframework.jdbc.CannotGetJdbcConnectionException",
  "message": "Could not get JDBC Connection; nested exception is java.sql.SQLException: Data source is closed",
  "path": "/ws_preRatesFilter/fetchFilterData"
}

Полная трассировка стека:

2015/10/20 08:19:19.216 ERROR o.s.b.c.w.ErrorPageFilter - Forwarding to error page from request [/fetchFilterData] due to exception [Could not get JDBC Connection; nested exception is java.sql.SQLException: Data source is closed]
org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: Data source is closed
    at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:80) ~[spring-jdbc-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:630) ~[spring-jdbc-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:695) ~[spring-jdbc-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:722) ~[spring-jdbc-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:772) ~[spring-jdbc-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:192) ~[spring-jdbc-4.1.8.RELEASE.jar:na]
    at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:199) ~[spring-jdbc-4.1.8.RELEASE.jar:na]
    at com.ws.preratesfilter.repository.FilterTableRepositoryImpl.getFilterData(FilterTableRepositoryImpl.java:65) ~[FilterTableRepositoryImpl.class:na]
    at com.ws.preratesfilter.repository.FilterTableRepositoryImpl$$FastClassBySpringCGLIB$$61dcca46.invoke(<generated>) ~[spring-core-4.1.8.RELEASE.jar:na]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.1.8.RELEASE.jar:na]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717) ~[spring-aop-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ~[spring-tx-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653) ~[spring-aop-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at com.ws.preratesfilter.repository.FilterTableRepositoryImpl$$EnhancerBySpringCGLIB$$63aae081.getFilterData(<generated>) ~[spring-core-4.1.8.RELEASE.jar:na]
    at com.ws.preratesfilter.service.FilterTableServiceImpl.getFilterData(FilterTableServiceImpl.java:30) ~[FilterTableServiceImpl.class:na]
    at com.ws.preratesfilter.controller.FilterTableController.fetchFilterData(FilterTableController.java:34) ~[FilterTableController.class:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_45]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_45]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_45]
    at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_45]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221) ~[spring-web-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) ~[spring-web-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110) ~[spring-webmvc-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:775) ~[spring-webmvc-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705) ~[spring-webmvc-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959) ~[spring-webmvc-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893) ~[spring-webmvc-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967) ~[spring-webmvc-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:869) ~[spring-webmvc-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:648) ~[servlet-api.jar:na]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843) ~[spring-webmvc-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) ~[servlet-api.jar:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291) [catalina.jar:8.0.24]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.24]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-websocket.jar:8.0.24]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.24]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.24]
    at org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration$ApplicationContextHeaderFilter.doFilterInternal(EndpointWebMvcAutoConfiguration.java:299) ~[spring-boot-actuator-1.2.7.RELEASE.jar:1.2.7.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.1.8.RELEASE.jar:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.24]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.24]
    at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:102) ~[spring-boot-actuator-1.2.7.RELEASE.jar:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.1.8.RELEASE.jar:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.24]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.24]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) ~[spring-web-4.1.8.RELEASE.jar:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.1.8.RELEASE.jar:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.24]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.24]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85) ~[spring-web-4.1.8.RELEASE.jar:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.1.8.RELEASE.jar:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.24]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.24]
    at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:76) ~[spring-boot-actuator-1.2.7.RELEASE.jar:1.2.7.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.1.8.RELEASE.jar:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.24]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.24]
    at org.springframework.boot.context.web.ErrorPageFilter.doFilter(ErrorPageFilter.java:116) [spring-boot-1.2.7.RELEASE.jar:na]
    at org.springframework.boot.context.web.ErrorPageFilter.access$000(ErrorPageFilter.java:60) [spring-boot-1.2.7.RELEASE.jar:na]
    at org.springframework.boot.context.web.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:91) [spring-boot-1.2.7.RELEASE.jar:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.1.8.RELEASE.jar:na]
    at org.springframework.boot.context.web.ErrorPageFilter.doFilter(ErrorPageFilter.java:109) [spring-boot-1.2.7.RELEASE.jar:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.24]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.24]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219) [catalina.jar:8.0.24]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) [catalina.jar:8.0.24]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) [catalina.jar:8.0.24]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) [catalina.jar:8.0.24]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [catalina.jar:8.0.24]
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:617) [catalina.jar:8.0.24]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) [catalina.jar:8.0.24]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518) [catalina.jar:8.0.24]
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091) [tomcat-coyote.jar:8.0.24]
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668) [tomcat-coyote.jar:8.0.24]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1527) [tomcat-coyote.jar:8.0.24]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1484) [tomcat-coyote.jar:8.0.24]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_45]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_45]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-util.jar:8.0.24]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_45]
Caused by: java.sql.SQLException: Data source is closed
    at org.apache.tomcat.dbcp.dbcp2.BasicDataSource.createDataSource(BasicDataSource.java:2015) ~[tomcat-dbcp.jar:8.0.24]
    at org.apache.tomcat.dbcp.dbcp2.BasicDataSource.getConnection(BasicDataSource.java:1532) ~[tomcat-dbcp.jar:8.0.24]
    at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111) ~[spring-jdbc-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77) ~[spring-jdbc-4.1.8.RELEASE.jar:4.1.8.RELEASE]
    ... 82 common frames omitted

2 ответа

Решение

В Spring Framework была проблема, исправленная в выпусках 4.2. В основном, если бин реализует Closeable его метод shutdown/close вызывается, даже если destroyMethod отключен (как Spring Boot).

Причина, по которой он работает с Tomcat7, а не с 8, вероятно, связана с тем, что tomcat8 использует некоторые новые языковые функции (AutoCloseable). При развертывании на Tomcat8 DataSource реализует этот дополнительный интерфейс и из-за ошибки вызывается метод shutdown.

Вы можете использовать Spring Framework 4.2.2.RELEASE с Spring Boot 1.2.x, чтобы воспользоваться этим исправлением прямо сейчас. Обновление до Spring Boot 1.3 позволит вам исправить эту ошибку стандартным способом.

А пока просто добавлю <spring.version>4.2.2.RELEASE</spring.version> так как вы используете spring-boot-starter-parent в вашем проекте.

Если вы не можете обновить до Spring Framework 4.2.x, другое решение - предоставить оболочку для источника данных. Что-то вроде

    @Bean
    public DataSource getJndiDataSource() {
        try {
            JndiTemplate jndiTemplate = new JndiTemplate();
            DataSource ds = (DataSource) jndiTemplate.lookup("java:comp/env/"+JNDI_DATASOURCE);
            return new DelegatingDataSource(ds);
        } catch(NamingException e){
            LOG.error("Could not find JNDI data source (java:comp/env/):"+JNDI_DATASOURCE, e);
            return null;
        }
    }

Делегирование источника данных не является AutoClosable и, следовательно, не будет закрыто Spring Framework.

Другие вопросы по тегам