天天看點

JVM類加載器應用之多版本庫支援

問題

  開發過程中,咱們經常需要使用不同的庫版本,而這些版本又不是向後相容的,或者出于某種原因需要支援同一庫的多個版本。

  在這種情況下,預設的類加載器已經是不支援了,因為 

loadClass

 方法隻加載一次特定的類,之後所有的加載請求就直接傳回現有 Class 執行個體的引用了。

解決辦法

  在這種情況下,可以自定義一個類加載器,用這個具有優先設定的加載器加載需要的庫就可以了。

基本代碼如下:

1 import java.net.URL;
 2 import java.net.URLClassLoader;
 3 import java.util.List;
 4 
 5 public class CustomClassLoader extends ClassLoader {
 6     private ChildClassLoader childClassLoader;
 7 
 8     public CustomClassLoader(List<URL> classpath) {
 9 
10         super(Thread.currentThread().getContextClassLoader());
11         URL[] urls = classpath.toArray(new URL[classpath.size()]);
12         childClassLoader = new ChildClassLoader(urls, new DetectClass(this.getParent()));
13     }
14 
15     @Override
16     protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
17         try {
18             return childClassLoader.findClass(name);
19         } catch(ClassNotFoundException e) {
20             return super.loadClass(name, resolve);
21         }
22     }
23 
24     private static class ChildClassLoader extends URLClassLoader {
25         private DetectClass realParent;
26 
27         public ChildClassLoader(URL[] urls, DetectClass realParent) {
28             super(urls, null);
29             this.realParent = realParent;
30         }
31 
32         @Override
33         public Class<?> findClass(String name) throws ClassNotFoundException {
34             try {
35                 Class<?> loaded = super.findLoadedClass(name);
36                 if(loaded != null) return loaded;
37                 return super.findClass(name);
38             } catch(ClassNotFoundException e) {
39                 return realParent.loadClass(name);
40             }
41         }
42     }
43 
44     private static class DetectClass extends ClassLoader {
45         public DetectClass(ClassLoader parent) {
46             super(parent);
47         }
48 
49         @Override
50         public Class<?> findClass(String name) throws ClassNotFoundException {
51             return super.findClass(name);
52         }
53     }
54 }      

All Done!

  至此就算完成了,通過這種解決辦法就可以使單個 jvm 中有多個庫版本,或者同一個版本中由于靜态變量導緻的多執行個體共存了。

注意:有些庫中可能還加載了一些 classpath 下的資源檔案,這種情況下就按需要覆寫 getResource 等方法就可以了。

極限就是為了超越而存在的