Hallo an die Runde,
ich habe eine kleine Applikation geschrieben, die als Impl. der JPA Hibernate 4 nutzt und die Dependency Injection erledige ich über Spring 4. Laufen soll es als RESTful JSON Service in einem Tomcat.
Abhängigkeiten verwalte ich mit Maven, womit ich auch den Bytecode erstelle und das WAR packe.
Ich kann alles bauen, die Applikation im Tomcat starten und den Service ansprechen. Der antwortet mir auch und alles sieht gut aus. Wird jedoch der REST-Request mehrfach angesprochen, so steht die ganze Sache. Der Request greift selbst auf die DB zu.
Stoppe ich dann den Tomcat, dann bekomme ich eine Exception gemeldet:
Ich denke richtig interessant sind die beiden Zeilen:
Schwerwiegend: The web application [/fbo-rest-srv-rest-service] registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
Schwerwiegend: The web application [/fbo-rest-srv-rest-service] appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it. This is very likely to create a memory leak.
Eigentlich ging ich davon aus, dass die Impl. über Spring korrekt verlief, aber es scheint nicht so zu sein. Konkret kann ich den Request 5 mal absetzen, danach antwortet der Server nicht mehr.
Meine Config für Hibernate sieht so aus:
Die web.xml sieht so aus:
und die mvc-dispatcher-servlet.xml hat diesen Inhalt:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
Index of /schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
Index of /schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- The controller needed to be found. -->
<context:component-scan base-package="de.bob.dpitest.webapp.controller" />
<import resource="classpath:META-INF/war-beans.xml" />
<mvc:annotation-driven />
</beans>
Vllt. auch noch relevant ist mein generisches DAO:
Eigentlich dachte ich, dass mit der Bean datasource und org.apache.tomcat.dbcp.dbcp2.BasicDataSource die Sache mit dem Pool erledigt ist. Oder muss ich hier konkret noch Hand am Tomcat anlegen.
Ich sehe es als Problem, dass der Connectionpool nicht "geleert" wird, bzw. die Connections nicht wieder geschlossen werden. Seht ihr das auch so?
ich habe eine kleine Applikation geschrieben, die als Impl. der JPA Hibernate 4 nutzt und die Dependency Injection erledige ich über Spring 4. Laufen soll es als RESTful JSON Service in einem Tomcat.
Abhängigkeiten verwalte ich mit Maven, womit ich auch den Bytecode erstelle und das WAR packe.
Ich kann alles bauen, die Applikation im Tomcat starten und den Service ansprechen. Der antwortet mir auch und alles sieht gut aus. Wird jedoch der REST-Request mehrfach angesprochen, so steht die ganze Sache. Der Request greift selbst auf die DB zu.
Stoppe ich dann den Tomcat, dann bekomme ich eine Exception gemeldet:
Code:
Apr 04, 2014 8:54:39 PM org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc
Schwerwiegend: The web application [/fbo-rest-srv-rest-service] registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
Apr 04, 2014 8:54:39 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
Schwerwiegend: The web application [/fbo-rest-srv-rest-service] appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it. This is very likely to create a memory leak.
Apr 04, 2014 8:54:39 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
Schwerwiegend: The web application [/fbo-rest-srv-rest-service] is still processing a request that has yet to finish. This is very likely to create a memory leak. You can control the time allowed for requests to finish by using the unloadDelay attribute of the standard Context implementation.
Apr 04, 2014 8:54:39 PM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
Schwerwiegend: The web application [/fbo-rest-srv-rest-service] created a ThreadLocal with key of type [org.springframework.core.NamedThreadLocal] (value [Request attributes]) and a value of type [org.springframework.web.context.request.ServletRequestAttributes] (value [org.apache.catalina.connector.RequestFacade@1f410757]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
Apr 04, 2014 8:54:39 PM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
Schwerwiegend: The web application [/fbo-rest-srv-rest-service] created a ThreadLocal with key of type [org.springframework.core.NamedThreadLocal] (value [Locale context]) and a value of type [org.springframework.web.servlet.DispatcherServlet$1] (value [org.springframework.web.servlet.DispatcherServlet$1@25dc4b6d]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
Apr 04, 2014 8:54:39 PM org.apache.coyote.AbstractProtocol stop
Information: Stopping ProtocolHandler ["http-bio-8080"]
log4j:WARN No appenders could be found for logger (org.hibernate.engine.jdbc.spi.SqlExceptionHelper).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Apr 04, 2014 8:54:39 PM org.apache.catalina.loader.WebappClassLoader loadClass
Information: Illegal access: this web application instance has been stopped already. Could not load org.hibernate.internal.util.JdbcExceptionHelper. The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact.
java.lang.IllegalStateException
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1588)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1547)
at org.hibernate.dialect.MySQLDialect$1.convert(MySQLDialect.java:444)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:126)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:112)
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:235)
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.getConnection(LogicalConnectionImpl.java:171)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.connection(StatementPreparerImpl.java:63)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:162)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:186)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:160)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1884)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1861)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1838)
at org.hibernate.loader.Loader.doQuery(Loader.java:909)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:354)
at org.hibernate.loader.Loader.doList(Loader.java:2551)
at org.hibernate.loader.Loader.doList(Loader.java:2537)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2367)
at org.hibernate.loader.Loader.list(Loader.java:2362)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:496)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:387)
at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:229)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1260)
at org.hibernate.internal.QueryImpl.list(QueryImpl.java:103)
at de.bob.dpitest.dao.impl.UserDao.findUserByEmailPassword(UserDao.java:29)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy29.findUserByEmailPassword(Unknown Source)
at de.bob.dpitest.service.impl.UserServiceImpl.getUserByEmailAndPassword(UserServiceImpl.java:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy31.getUserByEmailAndPassword(Unknown Source)
at de.bob.dpitest.webapp.controller.RestFulController.validateLogin(RestFulController.java:88)
at de.bob.dpitest.webapp.controller.RestFulController.getCities(RestFulController.java:116)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:214)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:690)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:945)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:876)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Ich denke richtig interessant sind die beiden Zeilen:
Schwerwiegend: The web application [/fbo-rest-srv-rest-service] registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
Schwerwiegend: The web application [/fbo-rest-srv-rest-service] appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it. This is very likely to create a memory leak.
Eigentlich ging ich davon aus, dass die Impl. über Spring korrekt verlief, aber es scheint nicht so zu sein. Konkret kann ich den Request 5 mal absetzen, danach antwortet der Server nicht mehr.
Meine Config für Hibernate sieht so aus:
Code:
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:property-placeholder location="classpath:persistence-mysql.properties" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="de.bob.dpitest.entity" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp2.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.user}" />
<property name="password" value="${jdbc.pass}" />
</bean>
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
</beans>
Die web.xml sieht so aus:
Code:
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>DPITest Rest</display-name>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/classes/log4j.properties</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
und die mvc-dispatcher-servlet.xml hat diesen Inhalt:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
Index of /schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
Index of /schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- The controller needed to be found. -->
<context:component-scan base-package="de.bob.dpitest.webapp.controller" />
<import resource="classpath:META-INF/war-beans.xml" />
<mvc:annotation-driven />
</beans>
Vllt. auch noch relevant ist mein generisches DAO:
Code:
package de.bob.dpitest.dao.common.impl;
import java.io.Serializable;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.google.common.base.Preconditions;
import de.bob.dpitest.dao.common.IOperations;
@SuppressWarnings("unchecked")
public abstract class AbstractHibernateDao<T extends Serializable> implements
IOperations<T> {
private Class<T> clazz;
@Autowired
private SessionFactory sessionFactory;
// API
protected final void setClazz(final Class<T> clazzToSet) {
clazz = Preconditions.checkNotNull(clazzToSet);
}
@Override
public final T findOne(final long id) {
return (T) getCurrentSession().get(clazz, id);
}
@Override
public final List<T> findAll() {
return getCurrentSession().createQuery("from " + clazz.getName())
.list();
}
@Override
public final void create(final T entity) {
Preconditions.checkNotNull(entity);
// getCurrentSession().persist(entity);
getCurrentSession().saveOrUpdate(entity);
}
@Override
public final T update(final T entity) {
Preconditions.checkNotNull(entity);
return (T) getCurrentSession().merge(entity);
}
@Override
public final void delete(final T entity) {
Preconditions.checkNotNull(entity);
Session session = this.getCurrentSession();
session.delete(entity);
session.flush();
}
@Override
public final void deleteById(final long entityId) {
final T entity = findOne(entityId);
Preconditions.checkState(entity != null);
delete(entity);
}
protected final Session getCurrentSession() {
// return sessionFactory.getCurrentSession();
return sessionFactory.openSession();
}
}
Eigentlich dachte ich, dass mit der Bean datasource und org.apache.tomcat.dbcp.dbcp2.BasicDataSource die Sache mit dem Pool erledigt ist. Oder muss ich hier konkret noch Hand am Tomcat anlegen.
Ich sehe es als Problem, dass der Connectionpool nicht "geleert" wird, bzw. die Connections nicht wieder geschlossen werden. Seht ihr das auch so?