Java 双亲委派问题&解决实战
Posted master-dragon
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 双亲委派问题&解决实战相关的知识,希望对你有一定的参考价值。
目录
java.lang.NoClassDefFoundError 问题引入
工程的3个模块介绍
源码见:https://github.com/doctording/bundle
- bundle-main 测试
- demo1 有一个Hello类
- demo2 有一个User类
- User类使用Hello类
- demo2模块依赖demo1且scope是provided
测试例子报错java.lang.NoClassDefFoundError
Exception in thread "main" java.lang.NoClassDefFoundError: com/dq/bundle/demo1/Hello
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at com.dq.bundle.main.Main.loaderErrorTest(Main.java:55)
at com.dq.bundle.main.Main.main(Main.java:23)
Caused by: java.lang.ClassNotFoundException: com.dq.bundle.demo1.Hello
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 7 more
附:测试代码 & 原因
static void loaderErrorTest() throws
MalformedURLException,
ClassNotFoundException,
IllegalAccessException,
InstantiationException,
NoSuchMethodException,
InvocationTargetException
Main m = new Main();
String filePath1 = "/Users/mubi/IdeaProjects/bundle/demo1/target/demo1-1.0-SNAPSHOT.jar";
URLClassLoader ul1 = new URLClassLoader(m.convert2URLArray(filePath1));
String filePath2 = "/Users/mubi/IdeaProjects/bundle/demo2/target/demo2-1.0-SNAPSHOT.jar";
URLClassLoader ul2 = new URLClassLoader(m.convert2URLArray(filePath2));
/**
* 正常加载Hello类
*/
Class<?> helloClass = ul1.loadClass("com.dq.bundle.demo1.Hello");
Object helloInstance = helloClass.newInstance();
Method sayMethod = helloClass.getMethod("say", String.class);
sayMethod.invoke(helloInstance, "world");
/**
* ul2 正常加载User类,但是无法加载其依赖的 Hello类,会报错ClassNotFoundException
*/
Class<?> userClass = ul2.loadClass("com.dq.bundle.demo2.User");
Object userInstance = userClass.newInstance();
Method welcomeMethod = userClass.getMethod("welcome", helloClass);
welcomeMethod.invoke(userInstance, helloInstance);
private URL[] convert2URLArray(String filePath) throws MalformedURLException
File f = new File(filePath);
URL[] urls = new URL[1];
urls[0] = f.toURI().toURL();
return urls;
原因:
Hello的类加载器cl1和User的类加载器cl2不一样;模块依赖使用的是provided;显然cl2是无法加载Hello类的,就会报错java.lang.NoClassDefFoundError
使用自定义类加载器解决
User的类加载器无法加载hello,可以在User的类加载器中引入Hello的类加载器,这样在一个模块中完成对User和Hello两个类的加载(即这里有一个新的自定义类加载器, 能实现对不同类的加载)
static void loaderErrorTest() throws
MalformedURLException,
ClassNotFoundException,
IllegalAccessException,
InstantiationException,
NoSuchMethodException,
InvocationTargetException
Main m = new Main();
String filePath1 = "/Users/mubi/IdeaProjects/bundle/demo1/target/demo1-1.0-SNAPSHOT.jar";
URLClassLoader ul1 = new URLClassLoader(m.convert2URLArray(filePath1));
String filePath2 = "/Users/mubi/IdeaProjects/bundle/demo2/target/demo2-1.0-SNAPSHOT.jar";
URLClassLoader ul2 = new URLClassLoader(m.convert2URLArray(filePath2));
/**
* 正常加载Hello类
*/
Class<?> helloClass = ul1.loadClass("com.dq.bundle.demo1.Hello");
Object helloInstance = helloClass.newInstance();
Method sayMethod = helloClass.getMethod("say", String.class);
sayMethod.invoke(helloInstance, "world");
/**
* ul2 正常加载User类,但是无法加载其依赖的 Hello类,会报错ClassNotFoundException
*/
Class<?> userClass = ul2.loadClass("com.dq.bundle.demo2.User");
Object userInstance = userClass.newInstance();
Method welcomeMethod = userClass.getMethod("welcome", helloClass);
welcomeMethod.invoke(userInstance, helloInstance);
static void selfLoaderTest() throws
MalformedURLException,
ClassNotFoundException,
IllegalAccessException,
InstantiationException,
NoSuchMethodException,
InvocationTargetException
Main m = new Main();
String filePath1 = "/Users/mubi/IdeaProjects/bundle/demo1/target/demo1-1.0-SNAPSHOT.jar";
URLClassLoader ul1 = new URLClassLoader(m.convert2URLArray(filePath1));
String filePath2 = "/Users/mubi/IdeaProjects/bundle/demo2/target/demo2-1.0-SNAPSHOT.jar";
SelfClassLoader ul2 = new SelfClassLoader(m.convert2URLArray(filePath2), ul1);
/**
* 正常加载Hello类
*/
Class<?> helloClass = ul1.loadClass("com.dq.bundle.demo1.Hello");
Object helloInstance = helloClass.newInstance();
Method sayMethod = helloClass.getMethod("say", String.class);
sayMethod.invoke(helloInstance, "world");
/**
* ul2正常加载User类, 并使用传递过来的ul1正常加载Hello类
*/
Class<?> userClass = ul2.loadClass("com.dq.bundle.demo2.User");
Object userInstance = userClass.newInstance();
Method welcomeMethod = userClass.getMethod("welcome", helloClass);
welcomeMethod.invoke(userInstance, helloInstance);
/**
* 自定义类加载器,可以传入其它类加载器
*/
static class SelfClassLoader extends URLClassLoader
private ClassLoader parentClassLoader;
public SelfClassLoader(URL[] urls, ClassLoader classLoader)
super(urls);
this.parentClassLoader = classLoader;
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException
Class<?> clazz = loadFromParent(name);
if (clazz != null)
return clazz;
return super.loadClass(name);
public Class<?> loadFromParent(String name)
// 从当前classLoader加载
Class<?> loadClass = super.findLoadedClass(name);
try
if (loadClass == null)
// 用父加载加载,这里是自己传入的类加载器
loadClass = this.parentClassLoader.loadClass(name);
catch (ClassNotFoundException e)
// e.printStackTrace();
return loadClass;
private URL[] convert2URLArray(String filePath) throws MalformedURLException
File f = new File(filePath);
URL[] urls = new URL[1];
urls[0] = f.toURI().toURL();
return urls;
使用arthas查看类加载信息
- Hello
- User
- User类的方法查看
以上是关于Java 双亲委派问题&解决实战的主要内容,如果未能解决你的问题,请参考以下文章