自定義ClassLoader 解決不同版本jar共存

1.有這樣一個變態需求,有兩個不同版本的dubbo.jar包,我們需要在項目中動態指定要運行哪個版本,改如何做?

不同版本jar包準備

package classloader;

public class Dubbo {
	public void invoke() {
		System.err.println("我是Dubbo的V1版本");
	}
}

將上面代碼export成dubbo-v1.jar
接下來準備另一個版本的,注意類的全路徑一定是相同的。

package classloader;

public class Dubbo {
	public void invoke() {
		System.err.println("我是Dubbo的V2版本");
	}
}

將上面代碼export成dubbo-v2.jar

客戶端將兩個jar引入,然後運行

public class Client {

	public static void main(String[] args) {
		Dubbo dubbo = new Dubbo();
		dubbo.invoke();
	}
}

程序運行:
我是Dubbo的V1版本

下面我們用一個比較爛的方法來進行解決,修改我們的客戶端

public class Client {

	public static void main(String[] args) throws Exception {
		invokeJar("C:/Users/皮吉/Desktop/dobbo-v1.jar");
		invokeJar("C:/Users/皮吉/Desktop/dobbo-v2.jar");

	}

	static class MyClassLoader extends ClassLoader {
		private String jarPath;

		public MyClassLoader(String jarPath) {
			this.jarPath = jarPath;
		}

		@Override
		public Class<?> loadClass(String className) throws ClassNotFoundException {
			byte[] b;
			try {
				// 只對我們的Dubbo類進行 class構造
				if (className.startsWith("classloader.Dubbo")) {
					b = findJar(className);
					return defineClass(className, b, 0, b.length);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			return super.loadClass(className);
		}

		// 從jar中找到指定class轉換成字節流
		private byte[] findJar(String className) throws IOException {
			String tmp = className.replaceAll("\\.", "/");
			@SuppressWarnings("resource")
			JarFile jar = new JarFile(jarPath);
			JarEntry entry = jar.getJarEntry(tmp + ".class");
			InputStream is = jar.getInputStream(entry);
			ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
			int nextValue = is.read();
			while (-1 != nextValue) {
				byteStream.write(nextValue);
				nextValue = is.read();
			}
			return byteStream.toByteArray();
		}

	}

	private static void invokeJar(String jar) throws Exception {
		MyClassLoader v = new MyClassLoader(jar);
		Class<?> clazz = v.loadClass("classloader.Dubbo");
		Object object = clazz.newInstance();
		Method method = clazz.getMethod("invoke", null);
		method.invoke(object, null);
	}
}

執行結果
在這裏插入圖片描述
這樣我們根據jar路徑,並且用自定義的classloader加載變成class,然後反射調用class,這是可行的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章