java.lang.NoClassDefFoundError: com/sun/mail/util/SharedByteArrayInputStream

java classloader体系结构
java classloader体系结构

最近碰到jar包冲突,抛出的异常:java.lang.NoClassDefFoundError: com/sun/mail/util/SharedByteArrayInputStream,导致发邮件发布出去。在线下无法重现,而线上确大部分情况都能重现。

在http://www.findjar.com搜了一下发现含有这个类的有mail-1.3.3.jar,而我工程里面使用的mail-1.4.5.jar。这样一来似乎把mail包的版本降低到1.3.3就行了。

but倔强的我不想降版本,所以不得不找出到底是哪里使用到了com.sum.mail.util.SharedByteArrayInputStream类,在网上百度了一番,发现j2ee.jar有嫌疑,我用的是j2ee-1.4.jar和mail-1.4.5.jar,把这个jar包使用jd反编译后看到了原因,j2ee-1.4.jar和mail-1.4.5.jar中都使用了javax.mail.internet.MimeMessage类,而j2ee-1.4.jar中的MimeMessage中import了com.sun.mail.util.SharedByteArrayInputStream类,mail-1.4.5.jar中的MimeMessage中import了javax.mail.util.SharedByteArrayInputStream类。在线下很可能mail-1.4.5.jar包中的MimeMessage类被优先load到jvm中,所以使用了javax.mail.util.SharedByteArrayInputStream类;而线上则很可能j2ee-1.4.jar中的MimeMessage类被优先load到jvm中,而com.sun.mail.util.SharedByteArrayInputStream类在整个web工程中确实不存在,所以出现了如题的异常。

这样一来解决的办法就是得升级j2ee.jar包,经查j2ee-5.jar使用MimeMessage类与mail-1.4.5.jar中的完全一样,都import的是javax.mail.util.SharedByteArrayInputStream类。这样把升级j2ee包到版本5就行了。

总结一下:j2ee-1.4.jar与mail-1.3.3jar匹配,j2ee-5.jar与mail-1.4.5.jar匹配即可避免jar包冲突。

mysql timeout setting using the Connector / J connection property ‘autoReconnect = true’ to avoid this problem.

最近发现应用隔段时间就不可用了,发现有如下的错误日志:

Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 45,012,127 milliseconds ago.  The last packet sent successfully to the server was 45,012,127 milliseconds ago. is longer than the server configured value of ‘wait_timeout’. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property ‘autoReconnect=true’ to avoid this problem.

经查,是因为默认的mysql的超时时间设置导致的:如果连接空闲超过8小时(即没有任何数据库操作),mysql会自动的断开与应用的链接,但可通过重启tomcat(或者其他web容器)的方式来解决。

以下是解决方案:

方案一

如果你的jdbc链接的url上没有autoReconnect=true参数的话,就添加类似下面的参数:

jdbc.url = jdbc:mysql ://ipaddress: 3306/database?autoReconnect=true&autoReconnectForPools=true

方案二

如果你使用了hibernate的话,还可以用下面的方式来配置:

<property name=”connection.autoReconnect”>true</property>
<property name=”connection.autoReconnectForPools”>true</property>
<property name=”connection.is-connection-validation-required”>true</property>

如果你使用的是c3p0连接池,可以这样配置:

<property name=”hibernate.c3p0.acquire_increment”>1</property>

<property name=”hibernate.c3p0.idle_test_period”>0</property>
<property name=”hibernate.c3p0.timeout”>0</property>
<property name=” hibernate. c3p0.validate”> true </property>

 方案三

最坏的方案:修改mysql的配置问加你my.cnf,wait_timeout 31536000就是一年,够长了:

[Mysqld]

wait_timeout = 31536000

interactive_timeout = 31536000

修改后,重启即可

或者参考这篇文章http://www.2cto.com/database/201312/261593.html动态修改超时时间。

值得注意的是,这种设置方法会对有的mysql上的所有数据库和所有客户端都有效,而往往不同的应用对超时时间的要求可能不尽相同,所以这种方法需要慎重使用。

Reference

http://www.databaseskill.com/2615216/

http://www.2cto.com/database/201312/261593.html