在帮朋友改bug时出现下面错误:
org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc The web application [] registered the JDBC driver [com.alibaba.druid.proxy.DruidDriver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
上面这个错误的意思是:
Web应用程序[]已注册JDBC驱动程序[com.alibaba.druid.proxy.druiddriver],但在Web应用程序停止时无法取消注册。为防止内存泄漏,JDBC驱动程序已强制取消注册。
这个错误是多次启动tomcat时出现的,第一次启动并没有报这个错
一开始我并没有怀疑是代码的问题,因为第一次启动并没有报这个错,后来无意中在web.xml中发现以下代码
当时在想这里加载这个监听器有什么用,要不先注释到再说,结果一注释启动就成功了,结果程序又出现了一点新问题,
页面一些数据没有加载进来。回过头来发现,这个监听器是用来初始化一些信息的。也就是下面这段代码
@Component
public class InitComponent implements ServletContextListener,ApplicationContextAware{
private static ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// TODO Auto-generated method stub
this.applicationContext=applicationContext;
}
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext application=servletContextEvent.getServletContext();
BloggerService bloggerService=(BloggerService) applicationContext.getBean("bloggerService");
Blogger blogger=bloggerService.find(); // 查询博主信息
blogger.setPassword(null);
application.setAttribute("blogger", blogger);
BlogTypeService blogTypeService=(BlogTypeService) applicationContext.getBean("blogTypeService");
List<BlogType> blogTypeCountList=blogTypeService.countList(); // 查询博客类别以及博客的数量
application.setAttribute("blogTypeCountList", blogTypeCountList);
BlogService blogService=(BlogService) applicationContext.getBean("blogService");
List<Blog> blogCountList=blogService.countList(); // 根据日期分组查询博客
application.setAttribute("blogCountList", blogCountList);
LinkService linkService=(LinkService) applicationContext.getBean("linkService");
List<Link> linkList=linkService.list(null); // 查询所有的友情链接信息
application.setAttribute("linkList", linkList);
}
public void contextDestroyed(ServletContextEvent sce) {
// TODO Auto-generated method stub
}
}
简单说下这个类的作用,它实现了ServletContextListener,ApplicationContextAware接口。
ServletContextListener接口用于tomcat启动时自动加载函数。
在Servlet API中有一个ServletContextListener接口,它能够监听ServletContext对象的生命周期,实际上就是监听Web应用的生命周期。
当Servlet容器启动或终止Web应用时,会触发ServletContextEvent事件,该事件由 ServletContextListener 来处理。在 ServletContextListener 接口中定义了处理ServletContextEvent事件的两个方法。
contextInitialized(ServletContextEvent sce):当Servlet容器启动Web应用时调用该方法。在调用完该方法之后,容器再对Filter初始化,并且对那些在Web应用启动时就需要被初始化的Servlet进行初始化。
contextDestroyed(ServletContextEvent sce):当Servlet容器终止Web应用时调用该方法。在调用该方法之前,容器会先销毁所有的Servlet和Filter过滤器。
这个J2EE小提示阐述了ServletContextListener的用法。这个事件类作为Web应用服务的一部分,处理Web应用的 servlet上下文(context)的变化的通知。这可以解释为,好像有个人在服务器旁不断地通知我们服务器在发生什么事件。那当然需要监听者了。因此,在通知上下文(context)初始化和销毁的时候,ServletContextListner非常有用。
ApplicationContextAware装配Bean
从已有的spring上下文取得已实例化的bean。通过ApplicationContextAware接口进行实现。
当一个类实现了这个接口(ApplicationContextAware)之后,这个类就可以方便获得ApplicationContext中的所有bean。换句话说,就是这个类可以直接获取spring配置文件中,所有有引用到的bean对象。
明白了这个的类的作用,问题也就好解决了。他不就是要初始化一些数据吗。
当时我想到了两种方法:
一是在请求页面前,先调用初始化数据的方法。
二是写一个SpringMVC的拦截器。
所以问题也就解决了
https://www.jianshu.com/p/4c0723615a52
https://blog.csdn.net/chunqiuwei/article/details/7694064
你还可以在web.xml配制监听,实现对jdbc连接的关闭。
首先在web.xml中加入一个监听:
<listener>
<listener-class>
com.xx.dbprovider.DBPooxDriverListener
</listener-class>
</listener>
- oxDriverListener实现ServletContextListener接口,在contextDestroyed对所有的驱动进行关闭
public class DBPooxDriverListener implements ServletContextListener {
private ServletContextEvent context=null;
@Override
public void contextDestroyed(ServletContextEvent destoryContext) {
// TODO Auto-generated method stub
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
try {
DriverManager.deregisterDriver(driver);
} catch (SQLException e) {
e.printStackTrace();
}
}
System.out.println("关闭所有数据库连接");
//destroyThreads();
}
@Override
public void contextInitialized(ServletContextEvent context) {
// TODO Auto-generated method stub
context=this.context;
}
/**
* 销毁未正常关闭的线程
*/
private void destroyThreads(){
final Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
if(thread.getName().equals("HouseKeeper")){
synchronized (this) {
try {
thread.interrupt();
return;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
public class WebAppContextListener implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent event) {
System.out.println("webService stop");
try {
while(DriverManager.getDrivers().hasMoreElements()) {
DriverManager.deregisterDriver(DriverManager.getDrivers().nextElement());
}
System.out.println("jdbc Driver close");
AbandonedConnectionCleanupThread.shutdown();
System.out.println("clean thread success");
} catch (SQLException e) {
e.printStackTrace();
}catch (InterruptedException e){
e.printStackTrace();
}
}
@Override
public void contextInitialized(ServletContextEvent event) {
Const.WEB_APP_CONTEXT = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());
}
}