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
的规则。
1
package
webcl;
2
3
import
java.net.URL;
4
import
java.net.URLClassLoader;
5
import
java.net.URLStreamHandlerFactory;
6
7
public
class
WebAppCL
extends
URLClassLoader {
8
9
public
WebAppCL(URL[] urls,
ClassLoader parent,
10
URLStreamHandlerFactory factory) {
11
super
(urls, parent, factory);
12
}
13
14
public
WebAppCL(URL[] urls, ClassLoader parent) {
15
super
(urls, parent);
16
}
17
18
public
WebAppCL(URL[] urls) {
19
super
(urls);
20
}
21
22
@Override
23
protected
synchronized
Class<?> loadClass(String name,
boolean
resolve)
24
throws
ClassNotFoundException {
25
try
{
26
return
findClass(name);
27
}
catch
(ClassNotFoundException ex) {
28
return
super
.loadClass(name, resolve);
29
}
30
}
31
32
}
这个ClassLoader
唯一的作用就是违反PD
的规则。
然后是App
程序:
1
package
test;
2
3
import
java.net.URL;
4
5
import
lib.IFac;
6
import
lib.MyData;
7
import
webcl.WebAppCL;
8
public
class
App2 {
//
应用程序的classpath
上有IFac
类和MyData
类。
9
public
static
void
main(String[] args)
throws
Exception {
10
MyData resolved =
new
MyData();
11
WebAppCL cl =
new
WebAppCL(
new
URL[] {
12
new
URL("file:\\C:\\Users\\zangmeng\\Desktop\\data.jar"),
//
包含MyData
类
13
new
URL("file:\\C:\\Users\\zangmeng\\Desktop\\faclib.jar")
});
//
包含FacImpl
类,不包含IFac
类。
14
IFac fac = (IFac)
cl.loadClass("faclib.FacImpl").newInstance();
15
MyData data = fac.getData();
16
}
17
}
程序在运行时,类加载情况如下所示:
程序很简单,四行代码而已。
第一行是创建一个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的实例。两个不同的类型,赋值自然会引发错误。
分享到:
相关推荐
NULL 博文链接:https://utopialxw.iteye.com/blog/1138133
el-api,java jar包,el表达式所需要的jar包。java.lang.LinkageError: loader constraints violated when linking javax/el/ExpressionFactory class;jar包冲突
启动Tomcat时报错:Caused by: java.lang.LinkageError: loader constraints violated when linking javax/el/ExpressionFactory class 说明:原因是juel.jar, juel-engine.jar, juel-impl.jar包和Tomcat6.0中的el-...
Burpsuite永久使用版,没有使用限制,V1.7.26版本,http抓包工具。
javax.servlet.ServletException: java.lang.LinkageError
java.lang.LinkageError: JAXB 2.0 API is being loaded from the bootstrap classloader, but this RI (from jar:file://build/web/WEB-INF/lib/jaxb-impl.jar!/com/sun/xml/bind/v2/model/impl/ModelBuilder.class...
日常使用 Java 开发,常常会遇到包依赖冲突的问题,尤其当工程应用变得臃肿庞大,包冲突的问题也会变得更加棘手,导致各种各样的报错,例如LinkageError, NoSuchMethodError等;实际开发中,可以采用多种方法来解决...
SOFAArk 最初的场景是解决 Java 开发常常会遇到的包依赖冲突的问题,尤其当工程应用变得臃肿庞大,包冲突的问题也会变得更加棘手,导致各种各样的报错,例如LinkageError, NoSuchMethodError等。实际开发中,可以...
其他还有很多异常,我就不一一列举了,我要说明的是,一个合格的程序员,需要对程序中常见的问题有相当的了解和...假设有类A和B(A不是B的父类或子类),O是A的实例,那么当强制将O构造为类B的实例时抛出该异常。该异常
MiMa可以报告二进制修改,这些修改可能导致JVM在运行时抛出java.lang.LinkageError (或其子类型之一,例如AbstractMethodError )。 链接错误通常是类/成员签名修改的结果。 MiMa比较了两个已发布库的所有类文件,...
背景日常使用 Java 开发,常常会遇到包依赖冲突的问题,尤其当工程应用变得臃肿庞大,包冲突的问题也会变得更加棘手,导致各种各样的报错,例如LinkageError, NoSuchMethodError等;实际开发中,可以采用多种方法来...
下载本包解压后放在%TOMCAT_HOME%和%JAVA_HOME%\lib下(jar包必须在endorsed 文件夹下)