javamail的bug

来源:互联网 发布:天津java培训学校 编辑:程序博客网 时间:2024/05/29 14:06
 

背景: 前天线上的tomcat突然挂了,一看原来网络连接超过了操作系统的限制

其实tomcat的压力也不大,并发也就20-30,怎么会造成这种情况,仔细观察发现好多

TCP连接Close_Wait, 这些连接都指向我们邮件中的附件资源,原来是我们发送带附件的邮件造成的

 

我们在发送邮件的程序中使用了URLDataSource,我在本地测试的时候也发现,在使用URLDataSource的情况下,确实会造成连接不关闭。

 

通过查看javamail的源代码,发现javamail也并非完全不关闭连接,在使用URLDataSource的时候会打开资源地址请求类型,也会通过流打开真正的资源,javamail获取资源后通过关闭流也关闭了资源的连接,但是获取资源类型的时候并未关闭连接

看看URLDataSource的源代码

 

  1. public String getContentType() {
  2. String type = null;
  3. try {
  4.     if (url_conn == null)
  5. url_conn = url.openConnection();
  6. catch (IOException e) { }
  7. if (url_conn != null)
  8.     type = url_conn.getContentType();
  9. if (type == null)
  10.     type = "application/octet-stream";
  11. return type;
  12.     }

URLDataSource并没有关闭类型连接的接口,所以一旦getContentType就没法关闭了,还好javamail的URLDataSource还是很好扩展的,解决办法如下

  1. public class XXURLDataSourceextends URLDataSource {
  2. public XXURLDataSource(URL arg0) {
  3. super(arg0);
  4. // TODO Auto-generated constructor stub
  5. }
  6. public String getContentType() {
  7. String type = null;
  8. java.net.HttpURLConnection url_conn = null;
  9. try {
  10. // if (url_conn == null)
  11. url_conn = (java.net.HttpURLConnection) this
  12. .getURL().openConnection();
  13. catch (IOException e) {
  14. }
  15. if (url_conn != null) {
  16. type = url_conn.getContentType();
  17. url_conn.disconnect();
  18. }
  19. if (type == null)
  20. type = "application/octet-stream";
  21. return type;
  22. }
  23. }

(这段程序仅支持http的资源类型,其他类型资源请自行解决)

 

产生一个类,继承URLDataSource ,并覆盖getContentType函数,然后在调用的地方把

URLDataSource 变为XXURLDataSource即可,本地测试没有问题,然后放在线上测试

发了3000封带附件的程序,系统fd一度高达3100+,后来在半小时内,fd逐渐回收,fd降到数百的正常水平,改造算是基本成功了

原创粉丝点击