关于weblogic中使用Dom4j、Xerces导致执行线程挂起的问题

关于weblogic中使用Dom4j、Xerces导致执行线程挂起的问题
        这两天有客户跟我说了个问题,说他们发现weblogic不停的load class,最后线程都挂在了Zip Entry操作上。让他们做了thread dump, 开始以为跟JDK的IO性能有关系,因为我曾经在HP\AIX上都碰到过线程挂起在zip操作上的问题,最终客户通过调整OS参数后,问题得到解决。但在拿到thread dump后, 发现问题不是他们说的那样,thread trace如下:

"ExecuteThread: '6' for queue: 'Out.Thread Pool'" daemon prio=5 tid=0005ff90 nid=54 lwp_id=1885955 waiting for monitor entry [0x239fa000..0x239f94f0]
 at java.util.zip.ZipFile.getEntry(ZipFile.java:161)
 - waiting to lock <35da8e78> (a sun.net.www.protocol.jar.URLJarFile)
 at java.util.jar.JarFile.getEntry(JarFile.java:194)
 at sun.net.www.protocol.jar.URLJarFile.getEntry(URLJarFile.java:89)
 at sun.net.www.protocol.jar.JarURLConnection.connect(JarURLConnection.java:95)
 at sun.net.www.protocol.jar.JarURLConnection.getInputStream(JarURLConnection.java:107)
 at java.net.URL.openStream(URL.java:913)
 at java.lang.ClassLoader.getResourceAsStream(ClassLoader.java:997)
 at javax.xml.parsers.FactoryFinder.find(FactoryFinder.java:160)
 at javax.xml.parsers.SAXParserFactory.newInstance(SAXParserFactory.java:87)
 at org.dom4j.io.JAXPHelper.createXMLReader(JAXPHelper.java:46)
 at org.dom4j.io.SAXHelper.createXMLReaderViaJAXP(SAXHelper.java:125)
 at org.dom4j.io.SAXHelper.createXMLReader(SAXHelper.java:78)
 at org.dom4j.io.SAXReader.createXMLReader(SAXReader.java:894)
 at org.dom4j.io.SAXReader.getXMLReader(SAXReader.java:715)
 at org.dom4j.io.SAXReader.read(SAXReader.java:435)
 at org.dom4j.DocumentHelper.parseText(DocumentHelper.java:278)
 ......

        我们可以看看SAXParserFactory.newInstance()的实现,

 1       public   static  SAXParserFactory newInstance()
 2           throws  FactoryConfigurationError
 3      {
 4           try
 5          {
 6               return  (SAXParserFactory)FactoryFinder.find( " javax.xml.parsers.SAXParserFactory " " org.apache.xerces.jaxp.SAXParserFactoryImpl " );
 7          }
 8           catch (FactoryFinder.ConfigurationError configurationerror)
 9          {
10               throw   new  FactoryConfigurationError(configurationerror.getException(), configurationerror.getMessage());
11          }
12      }

        再来看看FactoryFinder.find()的实现,

 1       static  Object find(String s, String s1)
 2           throws  ConfigurationError
 3      {
 4          debugPrintln( " debug is on " );
 5          ClassLoader classloader  =  findClassLoader();
 6           try
 7          {
 8              String s2  =  System.getProperty(s);
 9               if (s2  !=   null )
10              {
11                  debugPrintln( " found system property  "   +  s2);
12                   return  newInstance(s2, classloader);
13              }
14          }
15           catch (SecurityException _ex) { }
16           try
17          {
18              String s3  =  System.getProperty( " java.home " );
19              String s5  =  s3  +  File.separator  +   " lib "   +  File.separator  +   " jaxp.properties " ;
20              File file  =   new  File(s5);
21               if (file.exists())
22              {
23                  Properties properties  =   new  Properties();
24                  properties.load( new  FileInputStream(file));
25                  String s7  =  properties.getProperty(s);
26                  debugPrintln( " found java.home property  "   +  s7);
27                   return  newInstance(s7, classloader);
28              }
29          }
30           catch (Exception exception) { }
31          String s4  =   " META-INF/services/ "   +  s;
32           try
33          {
34              java.io.InputStream inputstream  =   null ;
35               if (classloader  ==   null )
36                  inputstream  =  ClassLoader.getSystemResourceAsStream(s4);
37               else
38                  inputstream  =  classloader.getResourceAsStream(s4);
39               if (inputstream  !=   null )
40              {
41                  debugPrintln( " found  "   +  s4);
42                  BufferedReader bufferedreader;
43                   try
44                  {
45                      bufferedreader  =   new  BufferedReader( new  InputStreamReader(inputstream,  " UTF-8 " ));
46                  }
47                   catch (UnsupportedEncodingException _ex)
48                  {
49                      bufferedreader  =   new  BufferedReader( new  InputStreamReader(inputstream));
50                  }
51                  String s6  =  bufferedreader.readLine();
52                  bufferedreader.close();
53                   if (s6  !=   null   &&   ! "" .equals(s6))
54                  {
55                      debugPrintln( " loaded from services:  "   +  s6);
56                       return  newInstance(s6, classloader);
57                  }
58              }
59          }
60           catch (Exception exception1) { }
61           if (s1  ==   null )
62          {
63               throw   new  ConfigurationError( " Provider for  "   +  s  +   "  cannot be found " null );
64          }  else
65          {
66              debugPrintln( " loaded from fallback value:  "   +  s1);
67               return  newInstance(s1, classloader);
68          }
69      }
70 

        看看两个方法的具体实现,这个问题基本一目了然了吧。 在我们要解析XML文件的时候,我们首先需要从parser factory获取一个parser实例,但parser factroy是什么? 我们需要去查找。仔细看一下这个查找顺序:
1:System property, JVM中是否定义了javax.xml.parsers.SAXParserFactory,这个可以通过-D设定
2:$JRE_HOME/ lib/jaxp.properties文件,是否存在javax.xml.parsers.SAXParserFactory键值对
3:xerces.jar文件的meta-inf/services/javax.xml.parsers.SAXParserFactory文件是否有值
4:当前classloader,是否存在org.apache.xerces.jaxp.SAXParserFactoryImpl,

        从thread dump可以看到,客户线程挂在了3上,因为1, 2条件不成立,所以走到了3, 而3每次都要打开jar文件,最终看到线程都停在了java.util.zip.ZipFile.getEntry()上。 解决方法:
1:启动JVM的时候,增加-Djavax.xml.parsers.SAXParserFactory=***
2::在$JRE_HOME/lib/增加jaxp.properties文件,其中定义javax.xml.parsers.SAXParserFactory=***
3:用展开的xerces.jar文件代替原有的jar文件

        客户同时提及了另外一个问题:我们有自己的parser factory, 为什么最后用了weblogic的? 而且不停的load class? Trace 如下:

"ExecuteThread: '42' for queue: 'OCS.Thread.Pool'" daemon prio=5 tid=004ca430 nid=245 lwp_id=1886146 waiting for monitor entry [0x1d9ba000..0x1d9ba4f0]
 at java.lang.ClassLoader.loadClass(ClassLoader.java:278)
 - waiting to lock <364cdf18> (a weblogic.utils.classloaders.GenericClassLoader)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:235)
 at weblogic.utils.classloaders.GenericClassLoader.loadClass(GenericClassLoader.java:224)
 at javax.xml.parsers.FactoryFinder.newInstance(FactoryFinder.java:93)
 at javax.xml.parsers.FactoryFinder.find(FactoryFinder.java:174)
 ......

        其实在上面的分析中可以看到,前三项中都没有找到parser factory, 那我们只能在当前class loader中去查找,并创建instance。因为你的应用部署在weblogic上, weblogic的classloader机制是, 所有的应用class loader都继承于weblogic application class loader, 所以你会看到weblogic class loader在trace中。但为什么不停的在class loader呢?其实看看JDK文档,并看看JDK的实现就能知道,
protected Class<?> loadClass(String name,
boolean resolve)
throws ClassNotFoundException
Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:

 

  1. Invoke findLoadedClass(String) to check if the class has already been loaded.

  2. Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.

  3. Invoke the findClass(String) method to find the class.

If the class was found using the above steps, and the resolve flag is true, this method will then invoke the resolveClass(Class) method on the resulting Class object.



 1       protected   synchronized  Class loadClass(String name,  boolean  resolve)
 2       throws  ClassNotFoundException
 3      {
 4       //  First, check if the class has already been loaded
 5      Class c  =  findLoadedClass(name);
 6       if  (c  ==   null ) {
 7           try  {
 8           if  (parent  !=   null ) {
 9              c  =  parent.loadClass(name,  false );
10          }  else  {
11              c  =  findBootstrapClass0(name);
12          }
13          }  catch  (ClassNotFoundException e) {
14               //  If still not found, then invoke findClass in order
15               //  to find the class.
16              c  =  findClass(name);
17          }
18      }
19       if  (resolve) {
20          resolveClass(c);
21      }
22       return  c;
23      }

        看看,其实能看到loadclass(),并不能说class loader一定在load class,更多的时候,他们是在find loaded class,否则怎么去创建对象?







你可能感兴趣的:(关于weblogic中使用Dom4j、Xerces导致执行线程挂起的问题)