Dubbo消费端java.lang.NoClassDefFoundError错误的排查

当时在代码中调用Dubbo服务时产生这个异常。

javax.servlet.ServletException: org.glassfish.jersey.server.
ContainerException: java.lang.NoClassDefFoundError: 
Could not initialize class com.xxxx.report.api.
ReportApiProvider$ReportApiProviderHolder

dubbo消费端代码结构如下:

public abstract class AbstractApiProvider {
    //省略
    ... 
    protected ResourceBundle dubboConsumer = ResourceBundle.getBundle("consumer/dubbo-consumer");
    // 省略
    ...
}

public class ReportApiProvider extends AbstractApiProvider {

    private ReportApiProvider() {
    }

    private static class ReportApiProviderHolder {
        private static final ReportApiProvider singleton = new ReportApiProvider();
    }

    static ReportApiProvider getInstance() {
        return ReportApiProviderHolder.singleton;
    }

    public static ReportService getReportService(){
        return getInstance().getBean(ReportService.class);
    }
}

调用getInstance()报错,但tomcat中却没有有效的日志,只有NoClassDefFoundError及调用栈信息。看到错误首先检查内部类相关的class是否成功编译,一切正常。

随后在排查过程中并未仔细检查父类AbstractApiProvider对资源的加载,导致排查多花了些时间。因为在父类中还完成了很多初始化工作,而且需要依赖很多其它的包。于是排查哪个包出现问题,通过每次替换一半的正常的依赖包并启动程序观察结果,于是很快定位到一个依赖包,替换了这个包后异常除。

随后再次分析ReportApiProvider的AbstractApiProvider,发现父类会获取属性文件中的属性,
ResourceBundle.getBundle(“consumer/dubbo-consumer”)最后去查找发现该方法尝试通过key去找value,这个(key,value)对并未配置在文件中,导致产生错误。

最后产生错误的完整路径是如下。
1. getInstance()
2. ReportApiProviderHolder.singleton
3. new ReportApiProvider()
4. 在基类中完成相关对象创建及资源加载
protected ResourceBundle dubboConsumer = ResourceBundle.getBundle(“consumer/dubbo-consumer”)最终失败,导致ReportApiProvider对象创建失败。

因此通过getInstance()获取实例时产生了
java.lang.NoClassDefFoundError:
Could not initialize class com.fengdai.report.api.ReportApiProvider$ReportApiProviderHolder异常。

随后又在stackoverflow上看了看相关问题。

http://stackoverflow.com/questions/34413/why-am-i-getting-a-noclassdeffounderror-in-java

最高票回答可以看出,在尝试加载类时因某些原来导致失败,进而产生了NoClassDefFoundError异常,而这个异常不仅仅是当.class不存在时候导致。

最后简化一下问题。下面的代码通过IODH单利模式获取对象实例,但由于基类基类加载时出错导致失败,导致ClassDefNotFoundError异常的产生。涉及的知识点
类加载机制参考深入《理解Java虚拟机 JVM高级特性与最佳实践》第7章即可。

abstract class AbstractLayer{
    private int a = 1/0;
}

class ConcretLayer extends AbstractLayer{
    private static class ConcretLayerHolder{
        private static final ConcretLayer singleton = new ConcretLayer();
    }

    public static  ConcretLayer getInstance(){
        return ConcretLayerHolder.singleton;
    }
}

public class ClassDefNotFoundError {
    public static void main(String[] args) {
        ConcretLayer.getInstance();
    }
}

你可能感兴趣的:(java,异常,DUBBO)