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,這是可行的。