融资租赁资产管理系统(FLAS)项目运维经验记录总结--org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl

问题:

xml解析抛异常,异常信息如下:

javax.servlet.ServletException: javax.xml.parsers.FactoryConfigurationError: Provider org.apache.xerces.jaxp.DocumentBuilderFactoryImpl not found
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:268)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:723)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:646)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:436)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:374)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
at org.apache.struts2.dispatcher.ServletDispatcherResult.doExecute(ServletDispatcherResult.java:164)
at org.apache.struts2.dispatcher.StrutsResultSupport.execute(StrutsResultSupport.java:191)
at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:372)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:276)
at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:189)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at app.base.interceptor.AuthenticationInterceptor.intercept(AuthenticationInterceptor.java:65)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at org.apache.struts2.interceptor.DeprecationInterceptor.intercept(DeprecationInterceptor.java:41)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:168)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265)
at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:76)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:229)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:229)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:191)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:73)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at org.apache.struts2.interceptor.DateTextFieldInterceptor.intercept(DateTextFieldInterceptor.java:125)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:91)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:253)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:140)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:193)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:189)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54)
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:567)
at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:81)
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:652)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:612)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:503)
at java.lang.Thread.run(Thread.java:745)
Caused by: javax.xml.parsers.FactoryConfigurationError: Provider org.apache.xerces.jaxp.DocumentBuilderFactoryImpl not found
at javax.xml.parsers.DocumentBuilderFactory.newInstance(DocumentBuilderFactory.java:127)
at org.apache.jasper.xmlparser.ParserUtils.parseXMLDocument(ParserUtils.java:128)
at org.apache.jasper.xmlparser.ParserUtils.parseXMLDocument(ParserUtils.java:194)
at org.apache.jasper.compiler.TagLibraryInfoImpl.parseTLD(TagLibraryInfoImpl.java:236)
at org.apache.jasper.compiler.TagLibraryInfoImpl.(TagLibraryInfoImpl.java:183)
at org.apache.jasper.compiler.Parser.parseTaglibDirective(Parser.java:386)
at org.apache.jasper.compiler.Parser.parseDirective(Parser.java:450)
at org.apache.jasper.compiler.Parser.parseElements(Parser.java:1400)
at org.apache.jasper.compiler.Parser.parse(Parser.java:130)
at org.apache.jasper.compiler.ParserController.doParse(ParserController.java:255)
at org.apache.jasper.compiler.ParserController.parse(ParserController.java:137)
at org.apache.jasper.compiler.Parser.processIncludeDirective(Parser.java:296)
at org.apache.jasper.compiler.Parser.parseIncludeDirective(Parser.java:333)
at org.apache.jasper.compiler.Parser.parseDirective(Parser.java:442)
at org.apache.jasper.compiler.Parser.parseElements(Parser.java:1400)
at org.apache.jasper.compiler.Parser.parse(Parser.java:130)
at org.apache.jasper.compiler.ParserController.doParse(ParserController.java:255)
at org.apache.jasper.compiler.ParserController.parse(ParserController.java:103)
at org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:185)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:354)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:334)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:321)
at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:592)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:328)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
... 78 more
Caused by: java.lang.ClassNotFoundException: org/apache/xerces/jaxp/DocumentBuilderFactoryImpl
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:278)
at javax.xml.parsers.FactoryFinder.getProviderClass(FactoryFinder.java:123)
at javax.xml.parsers.FactoryFinder.newInstance(FactoryFinder.java:178)
at javax.xml.parsers.FactoryFinder.newInstance(FactoryFinder.java:147)
at javax.xml.parsers.FactoryFinder.find(FactoryFinder.java:219)
at javax.xml.parsers.DocumentBuilderFactory.newInstance(DocumentBuilderFactory.java:121)
... 103 more

该问题会不定期爆发,集群3台服务器,2台用于用户访问使用,1台用于定时任务,2台用户访问的服务器每隔一周,基本就会出现一次这个问题,问题一旦出现,系统功能就会大面积瘫痪,无法正常使用;基本每次都是2台服务器中的随机一台出现此问题,头几次出现都是通过重启服务器解决的该问题,可是此问题频繁出现,影响系统的使用,因此觉得排查根本原因;

排查:

首先,排查的方法自然是老样子,先百度报错信息,网上对此报错有一些说法,比如jar包冲突问题,有的说删除xercesImpl.jar,使用JDK自带的xml解析等;还有的说在运行的代码通过setSysterProperty()的方式来处理;不过经过当时的分析,未发现网上所说的冲突jar包,并且报错地方并不是应用程序代码,而是其他jar包中的代码报错,因此百度中并未找到解决办法。

同时此问题也让其他同事帮忙解决,3个10年以上经验得同事和2个7年经验得同事也并未找到问题原因,至此问题暂时搁置,可是问题仍然每周至少出现一次,无奈职能继续排查问题,查看源码,经分析查看最后部分的异常信息,找到源代码位置,源代码如下(项目运行的jdk1.7,而我写这篇博客,个人电脑jdk1.8,因此异常信息和下面代码行数会不对应,不过不影响我表达的内容):

static  T find(Class type, String fallbackClassName)
        throws FactoryConfigurationError
    {
        final String factoryId = type.getName();
        dPrint("find factoryId =" + factoryId);

        // Use the system property first
        try {
            String systemProp = ss.getSystemProperty(factoryId);
            if (systemProp != null) {
                dPrint("found system property, value=" + systemProp);
                return newInstance(type, systemProp, null, true);
            }
        }
        catch (SecurityException se) {
            if (debug) se.printStackTrace();
        }

        // try to read from $java.home/lib/jaxp.properties
        try {
            if (firstTime) {
                synchronized (cacheProps) {
                    if (firstTime) {
                        String configFile = ss.getSystemProperty("java.home") + File.separator +
                            "lib" + File.separator + "jaxp.properties";
                        File f = new File(configFile);
                        firstTime = false;
                        if (ss.doesFileExist(f)) {
                            dPrint("Read properties file "+f);
                            cacheProps.load(ss.getFileInputStream(f));
                        }
                    }
                }
            }
            final String factoryClassName = cacheProps.getProperty(factoryId);

            if (factoryClassName != null) {
                dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName);
                return newInstance(type, factoryClassName, null, true);
            }
        }
        catch (Exception ex) {
            if (debug) ex.printStackTrace();
        }

        // Try Jar Service Provider Mechanism
        T provider = findServiceProvider(type);
        if (provider != null) {
            return provider;
        }
        if (fallbackClassName == null) {
            throw new FactoryConfigurationError(
                "Provider for " + factoryId + " cannot be found");
        }

        dPrint("loaded from fallback value: " + fallbackClassName);
        return newInstance(type, fallbackClassName, null, true);
    }

经过分析以上源代码可以看出,首先从systemProperty属性中读取实现类的全限定名,如果读取不到(没有设置过),那尝试从jdk中的lib下的jax.properties中读取,如果读取不到,再从web应用下引入的jar包中寻找(META-INF/services/javax.xml.parsers.DocumentBuilderFactory),最后依然找不到,就会使用jdk自带的com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl,可是根据以上分析,也未发现存在什么问题,项目中也存在对应的jar包,按理来讲,应该用第三种方式获取实现类全限定名,可是通过异常分析,结果却是走了第一种,走了第一种,一定是哪里调用了setSystemProperty()设置了相应的属性值,可是走了第一种又为什么会报错呢?推测类加载器加载不到对应的类,可是这里调用了哪种类加载器,为什么加载不到呢?带着这样的疑问,反编译jdk中JRE下的rt.jar,并且修改javax.xml.parsers.FactoryFinder及相关类中的方法,在各个关键点增加了日志输出,便于下次问题出现的时候可以准确的分析问题原因;不过同时也有个第二种考虑,就是在走第一种的时候,用try catch包裹异常,这样即使第一种报错,程序也会继续向下执行,不过这样就无法发现根因,并且同样需要修改jdk源码,因此采用了第一种方式,先寻找问题的根本原因。

果不其然,没过多久再一次发生了报错,这次经过查看日志信息,发现确实验证了我的推测,类加载器加载不到对应的类,当然并不是所有的走了第一种的都加载不到,而是当类加载为StandardClassLoader的时候加载不到,而WebAppClassLoader是可以加载到的,由于所加日志输出了类加载器信息,因此得知前者是后者的parent的关系,这里就涉及tomcat容器的类搜索顺序和jdk类搜索顺序了,jdk的类加载顺序是知道的,当时tomcat容器的并不知道,经过百度,有了初步的了解后大体理解了问题的原因。

可是接下来就要寻找解决方案了,直接原因就是项目中哪里调用了setSystemProperty()设置了相应的属性值,可是犹如大海捞针,应该如何去找呢,项目中的代码都搜索过了,并没有发现异常,最后决定从jar包中找答案;

因此对项目中所有jar包进行解押,然后压缩成一个文件,反编译这个文件,然后解押这个文件,最后利用EditPlus的文件夹所有文件全局搜索的方式,终于找到了问题所在,在某个功能模块的类中,static静态代码块中执行了该代码,因此只要点击该功能,加载了这个类,此段代码就会执行,至此找到了问题的根因,可是还是不知道怎么解决,为什么以前不报错,怎么突然就开始报错了呢?不过好在找到了根因,就可以进行测试验证了,通过操作这个功能模块,发现只有用户访问的2台服务器会报错,跑定时任务的那台服务器并不会报错,联想到那2台服务器是去你年底集群上线新加的服务器,可能是哪里配置不同,最后锁定到tomcat不同,经过对比发现,tomcat版本变高了,所以才导致某些情况下类加载器不同以及报错的问题。

解决:

最后通过对比跑定时任务的那台服务器和用户访问的2台服务器,发现其tomcat的版本不一样,2台用户访问的服务器版本较高,因此,将定时任务上面的tomcat整体迁移到这2台服务器上面,至此问题得到完美解决。

总结:

此次问题的解决过程,收获最大就是对类加载器的类加载机制的深入理解,比如不同类加载器对应的制定加载路径、tomcat加载类的搜索顺序,对于WebAppClassLoader优先从应用下加载,然后在向上传递,从顶层向下加载。

这篇博客主要用于记录个人项目经验,因此没有过多的准确表述和解释,我自己能看得懂即可,如果有遇到同样问题的小伙伴,有不懂的可以评论,我看到会解答的。

你可能感兴趣的:(java,线上问题,源码,java,运维)