tomcat下使用JNDI与JavaMail冲突问题

来源:互联网 发布:悉尼大学 住宿 知乎 编辑:程序博客网 时间:2024/06/09 13:48

声明:我不敢保证以下内容的正确性,内容仅供参考。有错误的地方,欢迎大家批评指正。下面的例子使用的tomcat版本是 6。

 

Java程序至少有三个类加载器

  Boot strap classloader  ---加载 jre/lib/rt.jar下的类。

    Ext classloader     --- 扩展的类加载器,加载jre/lib/ext下的类

      Appclassloader   --加载classpath下的类。

 

这些类加载器采用委托机制

 例如: 当App ClassLoader 加载 Demo.class。会先找它的父加载器Ext classloader,而Ext classloader又去找它的父加载器 Boot strap classloader。

Boot strap classloader去rt.jar下找,找到则完成加载,子加载器就不会加载了。没找到,

再由子类加载器加载。直到App classloader也没有找到类。就会抛出ClassNotFoundException异常。 这种机制可以保证内存中只有一份字节码。

例如,不会出现两个Object.class。

 

Tomcat定义的类加载器并没有采用委托父加载器去加载类的约定。只有当找不到类,才找父加载器。

 

Tomcat下有两个类加载器:

         WebappClassLoader:该加载器加载libclasses目录下的类。它的父加载器是StandardClassLoader

  以在tomcat6下加载的javax.mail.Session为例子,得到Session的加载器调用toString()得到如下信息

  session---WebappClassLoader

   context: /day23_web

  delegate: false  /* delegate翻译后是委托*/

   repositories:

     /WEB-INF/classes/

----------> Parent Classloader:

org.apache.catalina.loader.StandardClassLoader@c9be79a


   StandardClassLoader:该加载器加载tomcat下的lib目录下的类。比如使用JNDI获取的对象,就是此加载器加载类。这个类加载器是遵循父类委托机制的。它的父加载器是App classloader


Tomcat使用JNDI获取Session。发生ClassCaseException


例如: Sessionsession=(Session)envCtx.lookup("mail/Session");

 

首先:Sessionsession这个Session变量要创建就需要先加载类。这个时候使用的是WebappClassLoader加载。该加载器没有遵循委托父类机制,在加载类的时候,先自己找类加载,找不到再找父类。这个时候,lib目录下正好有Session类,那么便加载了该目录下的Session

envCtx.lookup("mail/Session");这是使用JNDI获取Session。那么,tomcat将会加载 tomcat/lib下面的Session。这个时候tomcat/lib下面正好有,也就加载了。不过使用的类加载器是StandardClassLoader

 

当程序执行到Sessionsession=(Session)envCtx.lookup("mail/Session");

实际上 session这个变量使用的字节码(Class)是WebappClassLoader中的Session.class。而使用JNDI envCtx.lookup("mail/Session");获取到的session对象是StandardClassLoader中的Session.class创建的。

 

两份不同字节码定义出的变量和对象。是不能兼容的。即使两个类加载器,加载的都是一份相同的,位置不同的字节码。

 

我想这可能是每个类加载到内存就会有一个唯一的标识吧,这个标识如果不能匹配。则被JVM认为不是同一份字节码。

 

解决这个问题,只需要将web工程下的lib目录下用于Javamail开发的那两个jar删掉,只保留tomcat/lib下的两个jar就行了。只要WebappClassloader找不到类,就会委托父类。这个时候定义的变量和使用JNDI获取的对象都是同一份字节码生成的,就不会产生ClassCastException了。





原创粉丝点击