tomcat 启动报错 registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister

在帮朋友改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());
		
	}
 
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值