java动态加载jar时,jar中还有第三方jar无法加载的解决方法

java动态加载jar时,jar中还有第三方jar无法加载的解决方法

当java插件化开发时,即一个java程序在运行的情况下动态加载另一个jar,网上大多数的方法如下

public static void main(String[] args)
			throws MalformedURLException, ClassNotFoundException, InstantiationException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
		String jarPath = "C:\\Users\\ricozhou\\Desktop\\tt.jar";
		File jarFile = new File(jarPath);
		String className = "test3.Test1";
		URL url = jarFile.toURI().toURL();
		ClassLoader system = new URLClassLoader(new URL[] { url }, Thread.currentThread().getContextClassLoader());
		Class<?> cs = system.loadClass(className);
		Object object = cs.newInstance();

		System.out.println(cs.getMethod("test").invoke(object));
	}

使用自定义类加载器加载,本来没什么问题,而且示例也都是一些简单的helloworld,但是当tt.jar中引入了第三方jar时,方法test中使用了第三方jar时,则会无法找到第三方类,如:创建一个项目,引入Common lang3

package test3;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;

public class Test1 {
	public static void main(String[] args) {
		System.out.println("执行main");
		System.out.println(StringUtils.isEmpty(null));
		System.out.println(StringUtils.isEmpty(""));

		System.out.println(ObjectUtils.anyNotNull(null, null));
		System.out.println(ObjectUtils.anyNotNull(11, null));

		System.out.println(RandomUtils.nextBoolean());
		System.out.println(RandomUtils.nextBoolean());

		System.out.println(SystemUtils.JAVA_HOME);
	}

	public void test() {
		System.out.println("执行test");
		System.out.println(StringUtils.isEmpty(null));
		System.out.println(StringUtils.isEmpty(""));

		System.out.println(ObjectUtils.anyNotNull(null, null));
		System.out.println(ObjectUtils.anyNotNull(11, null));

		System.out.println(RandomUtils.nextBoolean());
		System.out.println(RandomUtils.nextBoolean());

		System.out.println(SystemUtils.JAVA_HOME);
	}
}

导出为普通jar,注意不是可运行jar,因为这只是一个示例,以后可能这是一个类库,不需要main方法的,所以我都是直接打包成普通jar,这样再使用另一个项目动态加载这个jar,则会报错:

Exception in thread "main" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at test4.Test11.main(Test11.java:21)
Caused by: java.lang.NoClassDefFoundError: org/apache/commons/lang3/StringUtils
	at test3.Test1.test(Test1.java:14)
	... 5 more
Caused by: java.lang.ClassNotFoundException: org.apache.commons.lang3.StringUtils
	at java.net.URLClassLoader.findClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	... 6 more

找了好久都没有解决这个问题,最后发现,在jar中随便一个类中写一个main方法,然后打包成可执行jar,虽然是可执行jar但是不需要直接执行的,然后就可以了:

执行test
true
true
false
true
true
false
C:\Program Files\Java\jre1.8.0_191
null

如果需要在可执行jar的根目录添加一些文件,可以进行如下操作:

将打包的jar解压成文件夹:tt,然后将需要的文件复制到根目录

执行如下命令:

jar cvfM tt.jar -C tt\ .

cvfM中的M是为了忽略MANIFEST.MF,此文件很重要,原来什么样就什么样即可,不需要改变,所以忽略

特此记录一下,互相学习!

 

 

 

 

发布了56 篇原创文章 · 获赞 42 · 访问量 9万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章