LinkageError之loader (instance of xxx) previously initiated loading for a different type with name "lib/MyData"
2011-08-31 17:34
751 查看
LinkageError包括其子类,是Java中比较不应该出现的Error。出现这些问题,大概有几个问题:ClassLoader没有严格遵守Java中默认的双亲委派模式;全限定名相同的两个类在不同的CL中有重复;程序运行时使用的类的版本与开发时候不一样(类有变化,比如改了方法的可见性等)。
而LinkageError本身则更少见。当遇到LinkageError loader (instance of xxx) previously initiated loading for a different type with name "lib/MyData"时,可以肯定系统中有ClassLoader违背了Parent Delegate的规则。
问题的根源就是,当一个类已经被解析过之后,它用到的其它类也就已经确定并被解析好了。这时候,如果另一个CL也加载了同一个类(类名相同),并尝试将这个类的实例给前面的引用赋值,因为实际上两个类是由不同的类加载器加载的,既在JVM看来是不同的类,所以就会出现这个错误。
下面是一个简单的例子。没有实际意义,只为了展示问题。
系统中的几个角色类:
IFac - 接口,提供一个getMyData方法。
MyData - 数据类,没有实际意义,但是在系统中,这个类的加载则是引发问题的关键
IFacImpl - IFac接口的实现。
系统中还有一个不可或缺的角色——那个不遵守规则的ClassLoader。我们需要自己写一个ClassLoader来违法Parent Delegate的规则。
这个ClassLoader唯一的作用就是违反PD的规则。
然后是App程序:
程序在运行时,类加载情况如下所示:
程序很简单,四行代码而已。
第一行是创建一个MyData的实例。目的是让MyData类被加载和解析。
第二行是创建一个WebAppCL,这个不听话的CL会优先加载自己classpath下的类,如果失败了再去问parent cl要。现在这个CL可以加载MyData类和FacImpl类。
第三行,首先是IFac fac这段。JVM需要使用当前类加载器,也就是AppClassLoader,加载并解析IFac类,解析的过程中,同时链接到AppCL加载的MyData类。等号的另一边,通过WebCl加载并创建一个FacImpl的实例。这个时候,因为WebAppCL会首先从自己的CP里加载类,所以在解析FacImpl的时候,加载MyData的请求并没有被委派到AppCL,而是自己自己消化了,这时候JVM里面就有两个MyData类了。但是程序到这里并没有错误,因为WebAppCL里面并没有IFac接口,这个接口还是AppCL的,但是这时候隐患已经埋下了——
FacImpl类在解析的时候,需要MyData类,而这个MyData类是被WebCL加载的。
IFac则不同,它的MyData类是被AppCL加载的。
FacImpl实现了IFac接口,按说getMyData方法应该返回相同的类型。而在runti的时候,这两个MyData却是不同的类型,因为它们是被不同的CL加载的。
第四行是引起错误的地方。等号左边的MyData实际上是第一行中那个被AppCL加载的类的一个引用。等号右边返回的MyData实例是被WebCL加载的MyData的实例。两个不同的类型,赋值自然会引发错误。
而LinkageError本身则更少见。当遇到LinkageError loader (instance of xxx) previously initiated loading for a different type with name "lib/MyData"时,可以肯定系统中有ClassLoader违背了Parent Delegate的规则。
问题的根源就是,当一个类已经被解析过之后,它用到的其它类也就已经确定并被解析好了。这时候,如果另一个CL也加载了同一个类(类名相同),并尝试将这个类的实例给前面的引用赋值,因为实际上两个类是由不同的类加载器加载的,既在JVM看来是不同的类,所以就会出现这个错误。
下面是一个简单的例子。没有实际意义,只为了展示问题。
系统中的几个角色类:
IFac - 接口,提供一个getMyData方法。
MyData - 数据类,没有实际意义,但是在系统中,这个类的加载则是引发问题的关键
IFacImpl - IFac接口的实现。
系统中还有一个不可或缺的角色——那个不遵守规则的ClassLoader。我们需要自己写一个ClassLoader来违法Parent Delegate的规则。
package webcl; import java.net.URL; import java.net.URLClassLoader; import java.net.URLStreamHandlerFactory; public class WebAppCL extends URLClassLoader { public WebAppCL(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) { super(urls, parent, factory); } public WebAppCL(URL[] urls, ClassLoader parent) { super(urls, parent); } public WebAppCL(URL[] urls) { super(urls); } @Override protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { try { return findClass(name); } catch (ClassNotFoundException ex) { return super.loadClass(name, resolve); } } }
这个ClassLoader唯一的作用就是违反PD的规则。
然后是App程序:
package test; import java.net.URL; import lib.IFac; import lib.MyData; import webcl.WebAppCL; public class App2 { // 应用程序的classpath上有IFac类和MyData类。 public static void main(String[] args) throws Exception { MyData resolved = new MyData(); WebAppCL cl = new WebAppCL(new URL[] { new URL("file:\\C:\\Users\\zangmeng\\Desktop\\data.jar"), // 包含MyData类 new URL("file:\\C:\\Users\\zangmeng\\Desktop\\faclib.jar") }); // 包含FacImpl类,不包含IFac类。 IFac fac = (IFac) cl.loadClass("faclib.FacImpl").newInstance(); MyData data = fac.getData(); } }
程序在运行时,类加载情况如下所示:
程序很简单,四行代码而已。
第一行是创建一个MyData的实例。目的是让MyData类被加载和解析。
第二行是创建一个WebAppCL,这个不听话的CL会优先加载自己classpath下的类,如果失败了再去问parent cl要。现在这个CL可以加载MyData类和FacImpl类。
第三行,首先是IFac fac这段。JVM需要使用当前类加载器,也就是AppClassLoader,加载并解析IFac类,解析的过程中,同时链接到AppCL加载的MyData类。等号的另一边,通过WebCl加载并创建一个FacImpl的实例。这个时候,因为WebAppCL会首先从自己的CP里加载类,所以在解析FacImpl的时候,加载MyData的请求并没有被委派到AppCL,而是自己自己消化了,这时候JVM里面就有两个MyData类了。但是程序到这里并没有错误,因为WebAppCL里面并没有IFac接口,这个接口还是AppCL的,但是这时候隐患已经埋下了——
FacImpl类在解析的时候,需要MyData类,而这个MyData类是被WebCL加载的。
IFac则不同,它的MyData类是被AppCL加载的。
FacImpl实现了IFac接口,按说getMyData方法应该返回相同的类型。而在runti的时候,这两个MyData却是不同的类型,因为它们是被不同的CL加载的。
第四行是引起错误的地方。等号左边的MyData实际上是第一行中那个被AppCL加载的类的一个引用。等号右边返回的MyData实例是被WebCL加载的MyData的实例。两个不同的类型,赋值自然会引发错误。
相关文章推荐
- LinkageError之loader (instance of xxx) previously initiated loading for a different type with name
- previously initiated loading for a different type with name "javax/servlet/ServletContext"
- 【bug】previously initiated loading for a different type with name "javax/servlet/ServletContext"(142)
- previously initiated loading for a different type with name "javax/servlet/ServletContext"
- maven项目使用SOLR时报 previously initiated loading for a different type with name "javax/servlet/http/HttpServletRequest" 错的解决方法
- java Error:"The method xxx is undefind for the type of xxx"
- ava.lang.LinkageError: loader constraint violation:have different Class objects for the type setOper
- Error 47 "xxxxxxx"is an invalid value for the "InputManifest" parameter of the "GenerateApplicationM
- Directory lookup for the file "xxx.mdf" failed with the operating system error 2
- Cannot create an instance of OLE DB provider "OraOLEDB.Oracle" for linked server "xxxxxxx".
- The content of element type "struts-config" must match "(display-name?,description?,data-sources?,fo
- 关于[[NSBundle mainBundle] pathForResource:@"name" ofType:@"type"]找不到指定文件的解决办法
- type parameters of <T>T cannot be determined; no unique maximal instance exists for type variable T with upper bounds int,java.lang.Object
- An exception of type System.Data.SqlClient.SqlException was thrown. Additional exception information: A network-related or instance-specific error occ
- TypeError: name must be an instance of basestring
- (Entlib 5.0)Activation error occured while trying to get instance of type ICacheManager, key ""求解决办法
- 验证参数传递引发的Java编译错误“No enclosing instance of type XXX is accessible" 及匿名内部类
- HTTP Status 500 - java.lang.LinkageError: loader constraint violation: loader (instance of org/apach
- can not access a member of class com.xxx.MyClass with modifiers "public static final"
- Class.forName(xxx.xx.xx) ClassLoader.loadClass newInstance()区别