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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章