类加载器的相关问题(ClassLoader&&LinkageError)

原创 2004年12月29日 15:30:00

下面的错误在google上搜了半天也没有特别满意的答案,后来看到一篇关于JUnit类加载器Bug的文章,总算觉得柳暗花明....
  

java.lang.LinkageError: Class org/w3c/dom/Document violates loader constraints at
java.lang.ClassLoader.defineClass0(Native Method) at
java.lang.ClassLoader.defineClass(ClassLoader.java:502) at
java.lang.ClassLoader.defineClass(ClassLoader.java:431) at
.......

这样的异常,主要是由于非系统 类加载器,即自定义的类加载器出现了问题,这个类加载器试图加载org.w3c.dom.Document ,此时如果类加载器没有进行正确的处理,或者Document 类不在JVM's system classpath下,类加载器便无法加载,自己加载不了,也不通知系统类加载器,上面的错误就出现啦。。。

可能理解有问题,可参照下面这篇文章,我试验了一下,完全可信:


Here's a patch for JUnit's busted classloader: junit-patch.jar.  And below is XmlTest.java, a regression test that breaks (with a java.lang.LinkageError) with the old classloader and the swingui/awtui TestRunners, but passes with the patch.

junit-patch.jar contains two classes (source included):

  1. ReloadableTestClassLoader - a properly delegating custom ClassLoader that currently relies on a System property value for its classpath: junit.test.path. The fix can be ported to junit.runner.TestCaseClassLoader or it can be effected through a new ClassLoader like this one.
  2. ReloadingTestSuiteLoader - modified to return this custom ClassLoader. If I can get this fix applied to the real JUnit, this class wouldn't necessarily need to be modified (it's only like 5 lines) because we could fix the original TestCaseClassLoader instead of writing a new one. Whatever; minor detail.

XmlTest.java:

import junit.framework.TestCase;
import javax.xml.parsers.*;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
    
public class XmlTest extends TestCase {

Document doc = null; public void testXml() throws ParserConfigurationException { doc = DocumentBuilderFactory.newInstance() .newDocumentBuilder() .newDocument(); // System.out.println("Hello! I changed again"); Element root = doc.createElement("xml-test"); assertNotNull(root); } }

This is a simple test that reproduces a LinkageError with the JUnit buggy ClassLoader under the following conditions:

  1. Use Sun JDK 1.4.x
  2. Edit JUnit's excluded.properties so that you comment out the exclusion of org.w3c.dom.* -- this is necessary to reveal the bug and is the easiest test I could think of. Make sure your edited excluded.properties is first in the classpath or updated into junit.jar at junit/runner/excluded.properties (BTW, obviously the new ReloadableTestClassLoader doesn't use or rely on excluded.properties at all).
  3. Put the DOM interfaces (in Xerces these are in xml-apis.jar) and an XML parser impl, such as Xerces, in your classpath to reproduce the bug. Why? Since you will have unexcluded org.w3c.dom.* in excluded.properties, JUnit will attempt to load those interfaces rather than delegate to the system loader. But they aren't in the scope of JUnit's buggy classloader if they aren't in the JVM's system classpath, so you have to add them. I.e., the 1.4.x JVM loads these in its boot loader, whose classpath JUnit's buggy loader doesn't know about.
  4. Example of command line to use to reproduce the bug (using junit.jar from JUnit 3.8.1, but any version should work): java -cp .;junit.jar;xml-apis.jar;xerces.jar junit.swingui.TestRunner XmlTest

You should see this in the runner's error display window:

 java.lang.LinkageError: Class org/w3c/dom/Document violates loader constraints at
java.lang.ClassLoader.defineClass0(Native Method) at 
java.lang.ClassLoader.defineClass(ClassLoader.java:502) at 
java.lang.ClassLoader.defineClass(ClassLoader.java:431) at 
junit.runner.TestCaseClassLoader.loadClass(TestCaseClassLoader.java:104) at 
java.lang.ClassLoader.loadClass(ClassLoader.java:255) at 
java.lang.ClassLoader.loadClassInternal(ClassLoader.java:315) at 
XmlTest.testXml(XmlTest.java:16) at 
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at 
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at 
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at 
java.lang.reflect.Method.invoke(Method.java:324) at 
junit.framework.TestCase.runTest(TestCase.java:154) at 
junit.framework.TestCase.runBare(TestCase.java:127) at 
junit.framework.TestResult$1.protect(TestResult.java:106) at 
junit.framework.TestResult.runProtected(TestResult.java:124) at 
junit.framework.TestResult.run(TestResult.java:109) at 
junit.framework.TestCase.run(TestCase.java:118) at 
junit.framework.TestSuite.runTest(TestSuite.java:208) at 
junit.framework.TestSuite.run(TestSuite.java:203) at 
junit.swingui.TestRunner$16.run(TestRunner.java:623)

Now run the same test with the fixed ClassLoader:

  1. shadow classes in junit.jar by listing junit-patch.jar first in the classpath
  2. set junit.test.path property to include the path to XmlTest.class
  3. run XmlTest with the Swing or AWT test runner:
    java -cp junit-patch.jar;junit.jar -Djunit.test.path=. junit.swingui.TestRunner XmlTest

关于类加载器内存泄露的分析

从上个世纪90年代Java诞生之日起,Java的类和资源的加载就一直是个问题。由于它增加了启动和初始化时间,因此这个问题在Java应用服务器上则尤为明显。为了缓解这个问题,大家试过了不同的访问,比如说...
  • jie1991liu
  • jie1991liu
  • 2014年04月26日 22:56
  • 887

扩展类加载器的加载问题

我们都知道java的类载入器共有三级,分别是bootstrap (引导类)加载器、extension(扩展类)加载器和 system (系统类)加载器。这三个加载器是父子关系,其中 bootstrap...
  • dlf123321
  • dlf123321
  • 2014年10月24日 18:17
  • 1654

深入类加载器----类加载器的分类和等级

深入类加载器(三)----类加载器的分类和等级                      深入类加载器层次结构(三种类加载器)代理加载模式,双亲委托机制    我们首先要知道在jav...
  • li12412414
  • li12412414
  • 2016年08月13日 00:37
  • 1176

类加载器深入理解

Java类加载器深入理解,包括类加载器的命名空间、类加载器的双亲委派模型的实现原理、Tomcat类加载器体系结构...
  • sunxianghuang
  • sunxianghuang
  • 2016年08月11日 23:21
  • 3482

Tomcat类加载器(附JVM类加载器简介)

Tomcat类加载器(附JVM类加载器简介)          学习tomcat类加载器,首先得先看下JVM提供了几种类加载器,毕竟tomcat类加载器是依赖于JVM类加载器的。         ...
  • lantian0802
  • lantian0802
  • 2013年04月13日 17:56
  • 1954

Java基础---内省、注解、类加载器 (黑马程序员)

第一讲     内省引出JavaBean 一、内省         1、内省对应的英文单词为IntroSpector,英文意思是检查、视察、体检之意,对于程序即对内部进行检查,了解更多的底层细节。...
  • u011870547
  • u011870547
  • 2015年04月08日 10:38
  • 615

类加载器获取资源路径

一、同一工程中: String path = Thread.currentThread().getContextClassLoader().getResource(".").getPath(...
  • Sco_Pis
  • Sco_Pis
  • 2016年06月22日 23:58
  • 1673

JVM类加载器原理与自定义类加载器

一、类加载器原理 JVM将class文件字节码文件加载到内存中, 并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个代表这个类的java.lang.Class 对象,作为方法区类数据的...
  • scgaliguodong123_
  • scgaliguodong123_
  • 2015年07月17日 16:35
  • 2032

Java类加载器(自定义类加载器)

为什么要有类加载器 类加载的过程 初识类加载器 类加载机制 自定义类加载器 为什么要有类加载器我们知道java中所有的二进制文件,最后都是要放在jvm中解释运行的。纯粹的二进制文件,其实并没有什么卵用...
  • luochoudan
  • luochoudan
  • 2016年03月03日 15:42
  • 1844

自定义类加载器的实现

Java的类加载器自从JDK1.2开始便引入了一条机制,叫做父类委托机制。也就是说,一个类需要被加载的时候, JVM先会调用他的父类加载器进行加载。如果父类加载器加载不了,再使用其子类进行加载。当然...
  • a352193394
  • a352193394
  • 2012年03月12日 08:08
  • 7460
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:类加载器的相关问题(ClassLoader&&LinkageError)
举报原因:
原因补充:

(最多只允许输入30个字)