Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
922 views
in Technique[技术] by (71.8m points)

spring mvc - 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
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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:


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...