竹子开花的时 发表于 2017-1-25 10:35:44

Tomcat类装载的问题.

昨天发布一个web application的时候发现一个奇怪的问题, 明明jar包里面有的类说找不到, 真是奇怪. 不过要下班了. 明天再说吧.
java.lang.NoClassDefFoundError: com/netsboss/util/dbobject/GeneralEntity
java.lang.ClassLoader.defineClass1(Native Method)
java.lang.ClassLoader.defineClass(ClassLoader.java:620)
java.lang.ClassLoader.defineClass(ClassLoader.java:465)
com.netsboss.util.proxy.ProxyClassLoader.defineClass(ProxyClassLoader.java:75)
com.netsboss.util.proxy.Proxy.getProxyClass(Proxy.java:216)
com.netsboss.util.dbobject.DatabaseManager.generateClass(DatabaseManager.java:1161)
com.netsboss.util.dbobject.DatabaseManager.<init>(DatabaseManager.java:240)
com.netsboss.util.dbobject.DatabaseManager.getDatabaseManager(DatabaseManager.java:98)
com.aft.constants.SystemConstants.getDefaultAFTDatabaseManager(SystemConstants.java:258)
com.aft.database.retrieve.CAFTDBGetWebUserInfo.<init>(CAFTDBGetWebUserInfo.java:64)
com.aft.database.retrieve.CAFTDBGetWebUserInfo.getCAFTDBGetWebUserInfo(CAFTDBGetWebUserInfo.java:51)
com.aft.servlets.actions.RegisterAction.perform(RegisterAction.java:43)
org.apache.struts.action.Action.execute(Action.java:420)
org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:484)
org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:274)
org.apache.struts.action.ActionServlet.process(ActionServlet.java:1482)
org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:525)
javax.servlet.http.HttpServlet.service(HttpServlet.java:709)
javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
上面的是异常的信息, 我明明把含有这个类的jar包放到了WEB-INF/lib下面. 怎么办,还能这么办, trace code.
结果发现在了一个自定义的类装载器com.netsboss.util.proxy.ProxyClassLoader,他在构着函数里面没有传他的parent classloader(tomcat Webapp classloader)进去, 所以他的parent classloader是systemclassloader, 我想假如ProxyClassLoader的构着函数里面调用了super(ProxyClassLoader.class.getClassLoader());的话,
 应该能解决这个问题的. 我想这个就是这个java.lang.NoClassDefFoundError异常的原因吧.   
这里有篇介绍类装载的问题, 也介绍了Tomcat类装器的机制.
http://blog.csai.cn/blog/number01/2005628165135.html
添加一些: 这个是自定义的classloader, 他在构着函数里面没有传他的parent classloader(tomcat Webapp classloader)进去, 所以他的parent classloader是systemclassloader,具体代码看java.lang.ClassLoader.   /**
   * Creates a new class loader using the specified parent class loader for
   * delegation.
   *
   *  If there is a security manager, its {@link
   * SecurityManager#checkCreateClassLoader()
   * checkCreateClassLoader} method is invoked.This may result in
   * a security exception.

   *
   * @paramparent
   *         The parent class loader
   *
   * @throwsSecurityException
   *          If a security manager exists and its
   *          checkCreateClassLoader method doesn&apost allow creation
   *          of a new class loader.
   *
   * @since1.2
   */
    protected ClassLoader(ClassLoader parent) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
   security.checkCreateClassLoader();
}
this.parent = parent;
initialized = true;
    }    /**
   * Creates a new class loader using the ClassLoader returned by
   * the method {@link #getSystemClassLoader()
   * getSystemClassLoader()} as the parent class loader.
   *
   *  If there is a security manager, its {@link
   * SecurityManager#checkCreateClassLoader()
   * checkCreateClassLoader} method is invoked.This may result in
   * a security exception.

   *
   * @throwsSecurityException
   *          If a security manager existsand its
   *          checkCreateClassLoader method doesn&apost allow creation
   *          of a new class loader.
   */
    protected ClassLoader() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
   security.checkCreateClassLoader();
}
this.parent = getSystemClassLoader();
initialized = true;
    } package com.netsboss.util.proxy; import java.io.File;import java.io.FileOutputStream;import java.io.IOException;
import java.io.UnsupportedEncodingException;import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;import java.util.HashMap;
import java.util.Locale;import org.apache.log4j.Category; public class ProxyClassLoader extends ClassLoader {private static Category log = Category.getInstance(ProxyClassLoader.class); private HashMap classes = new HashMap(); private boolean saveToClassPath = false;public ProxyClassLoader(boolean saveToClassPath){this.saveToClassPath = saveToClassPath; }/*** @see ClassLoader#findClass(String)*/ protected Class findClass(String name) throws ClassNotFoundException {   Class find = super.findClass(name);if(find != null) return find;   find = (Class)classes.get(name);if(find != null) return find;else throw new ClassNotFoundException(name);}public void defineClass(byte classfile[], String classname){   Class clazz = defineClass(classname, classfile,0, classfile.length);classes.put(classname,clazz);   if(saveToClassPath){   saveToClassPath(classfile, classname);}}/*** return a class which implements all the interfaces or inherit from one of class* currently, just return null.*/ public Class search(Class interfaces[]){return null; }private void saveToClassPath(byte classfile[], String classname){String filename = classname + ".class";   URL url = getClass().getProtectionDomain().getCodeSource().getLocation();if( "file".equals(url.getProtocol()) && (url.getHost() == null || url.getHost().equals("")) ){      String dir = null;      try{
      dir = URLDecoder.decode(url.getFile(), "UTF-8");
      }catch(UnsupportedEncodingException ex){
      log.error("Encoding not supported", ex);
      }    File classpath = new File(dir);   if(classpath.isDirectory() == false){    log.info("Classpath error for ProxyClassLoader:" + dir + " not a directory");    return;   }   File file = new File(classpath, filename);   try {    FileOutputStream os = new FileOutputStream(file);    os.write(classfile);    os.close();   }   catch(IOException ex){
      log.error("Error writing Proxy Class file", ex);
    ex.printStackTrace();   }}} }参考这篇文章http://www.cjsdn.net/post/view?bid=29&id=162060&sty=1&tpg=1&age=0
页: [1]
查看完整版本: Tomcat类装载的问题.