Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The web application [] registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped

I've seen few similar issues on stackoverflow but i could not figure out how i can solve my problem. After adding Spring Security to my Spring MVC project i got following exception:

Jul 20, 2014 3:18:04 PM org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc
SEVERE: The web application [] 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.

Here is my mysql-connecter in the pom.xml

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.31</version>
    </dependency>

Here are classes that i've added:

@Component
@Transactional
public class UserDetailsServiceImpl implements UserDetailsService{

@Autowired
private UserDAO userDAO;

@Autowired
private UserAssembler userAssembler;

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

@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
    User user = userDAO.findByEmail(username);

    if(null == user) throw new UsernameNotFoundException("User not found");

    return userAssembler.buildUserFromUser(user);
}
}

and assembler

 @Service("assembler")

public class UserAssembler {

@Autowired
private UserDAO userDAO;

@Transactional(readOnly = true)
public User buildUserFromUser(net.viralpatel.contact.model.User user) {
    String role = "ROLE_USER";//userEntityDAO.getRoleFromUserEntity(userEntity);

    Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    authorities.add(new GrantedAuthorityImpl(role));

    return new User(user.getLogin(), user.getPassword(), true, true, true, true,  authorities);
}
}

Here is my spring-security.xml

<beans:bean id="webexpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler" />

<http auto-config="true">
    <intercept-url pattern="/account/*" access="ROLE_ADMIN" />
    <form-login login-page="/login" default-target-url="/account/overview" authentication-failure-url="/login?error=true"/>
    <remember-me/>
</http>

<beans:bean id="myUserDetailsService" class="net.viralpatel.contact.service.UserDetailsServiceImpl" />


<authentication-manager alias="authenticationManager">
    <authentication-provider user-service-ref="myUserDetailsService" />
</authentication-manager>

EDITED:

INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /opt/idea-IU-135.909/bin::/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
Jul 20, 2014 3:58:36 PM org.apache.catalina.core.JreMemoryLeakPreventionListener lifecycleEvent
SEVERE: Failed to load class com.mysql.jdbc.NonRegisteringDriver during Tomcat start to prevent possible memory leaks.
java.lang.ClassNotFoundException: com.mysql.jdbc.NonRegisteringDriver
like image 454
user3127896 Avatar asked Jul 20 '14 11:07

user3127896


2 Answers

Your application doesn't have a flaw. It is the design of JDBC. The JDBC driver gets loaded and registered by the webapp when it creates a database connection for the first time.

That means that the driver is loaded with the web application class loader. On undeployment the driver doesn't get deregistered which in turn prevents your webapp classes from GC. That creates effectively a memory leak.

To prevent this particular memory leak you should edit your tomcat/conf/server.xml and change

<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />

to

<Listener 
className="org.apache.catalina.core.JreMemoryLeakPreventionListener"
classesToInitialize="com.mysql.jdbc.NonRegisteringDriver" />
  • With mysql-connector-java-8.0.x use com.mysql.cj.jdbc.NonRegisteringDriver instead

Exclude the JDBC driver from your webapp artifact and put it into the tomcat/lib directory. Now the JDBC driver gets loaded by Tomcat on startup and isn't linked to any webapps class loader.

Why should I modify the server.xml?

Another memory leaks manifests due to MySQL's 'Abandoned connection cleanup thread'. This thread starts with the first request and holds a reference to the webapp's classloader. With classesToInitialize you can prevent this memory leak too.

References:

  • org.apache.catalina.core.JreMemoryLeakPreventionListener tomcat-doc v7.0
  • AbandonedConnectionCleanupThread notes in v5.1.41
  • com.mysql.jdbc.NonRegisteringDriver source v5.1
  • com.mysql.cj.jdbc.NonRegisteringDriver source v8.0
  • mysql-connector-java changes in v8.0
like image 123
ksokol Avatar answered Nov 15 '22 11:11

ksokol


What I did was just to put the mysql-connector-java-5.1.31-bin.jar in $CATALINA_HOME/lib. No modifications to server.xml.

like image 23
Titi Wangsa bin Damhore Avatar answered Nov 15 '22 13:11

Titi Wangsa bin Damhore