tomcat启动失败时的ClassNotFoundException

tomcat在部署应用时,如果部署失败,该应用会被stop,但如果该应用的WebappClassLoader被其它线程持有并且继续使用的话,可能发生异常。

应用部署失败被stop的时候,classLoader也被stop(因为WebappClassLoader实现了Lifecycle接口),stop的时候,相关的 files/jars/resoures/repositories/parent 等等都被清除掉了,同时标识应用是否启动的started状态也被设置为false;基本上该classloader已经不可用了。(除了还可以委托给j2seClassLoader这个bootstrap classloader,这个classloader实际运行时是ExtClassLoader)

假设应用里有一个类自己启动了一个线程,逻辑大致如下:

static {
    new Thread(){
        public void run(){
            // 1) 先sleep一段时间,确保应用完成初始化
            // 2) 然后执行一些逻辑
        }
    }.start();
}

上面线程在执行后续逻辑的时候,使用WebappClassLoader去加载类,如果在sleep的阶段app在tomcat中没有启动成功,被stop了,则后边的逻辑有些意思。

看一下loadClass方法:

    public synchronized Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException {

    if (log.isDebugEnabled())
        log.debug("loadClass(" + name + ", " + resolve + ")");
    Class<?> clazz = null;

    // Log access to stopped classloader
    if (!started) {
        try {
            throw new IllegalStateException(); //这里抛出异常,又被自己捕获
        } catch (IllegalStateException e) {
            log.warn(sm.getString("webappClassLoader.stopped", name));
        }
    }

    // (0) Check our previously loaded local class cache
    ...

    // (0.1) Check our previously loaded class cache
    ...

    // (0.2) Try loading the class with the system class loader, to prevent
    //       the webapp from overriding J2SE classes
    ...

    // (0.5) Permission to access this class when using a SecurityManager
    ...

    // (1) Delegate to our parent if requested
    ...

    // (2) Search local repositories
    ...

    // (3) Delegate to parent unconditionally
    ...

    throw new ClassNotFoundException(name);

}

loadClass方法里判断了started状态,未启动的情况下,抛出异常,又自己捕获,仅仅记录了一下日志。然后继续后边的逻辑,先从cache里找,然后委托j2se classloader,再委派parent classloader,以及从本地仓库寻找。找不到抛出ClassNotFoundException

前面提过应用在stop时webappclassloader里的cache/parent等有关资源都被清空了,如果应用里启动的线程后续逻辑要求找的类,不是j2seclassloader可以找得到的类的话,就会抛出异常。

很多情况下,开发人员总是被这个ClassNotFoundException所迷惑, 如果仔细看日志的话,已经给出了应用被stopped的信息:

2014-6-17 21:58:42 org.apache.catalina.loader.WebappClassLoader loadClass  
信息: Illegal access: this web application instance has been stopped already.    

发表评论

电子邮件地址不会被公开。 必填项已用*标注