posts - 28, comments - 37, trackbacks - 0, articles - 0
               最近這些天學習了classLoader的原理, 原因是因為服務器上的一個java進程啟動時加載兩個不同版本的jar包, 含有相同名字的類, 而且服務端的jar包排在前面, 我上傳的jar包排在后面, 于是每次都使用服務端的jar包, 我的jar包便無法生效, 因此希望修改classLader, 讓它按相反的順序加載jar包.
               網上查閱了classLoader的原理, 分析jvm默認使用AppClassLoader加載classpath中的類, 因此目標很明確, 替換它就行了, 找到一個參數
          java.system.class.loader, 只需要在啟動java進程的時候把它設置為自己的類就行.
               開始寫自己的classLoader, 參考URLClassLoader與網上的介紹, 寫了一個簡單的,上代碼:
            1 package org.taobao.yuling.testClassLoader;
            2 
            3 import java.io.*;
            4 import java.lang.reflect.*;
            5 import java.net.MalformedURLException;
            6 import java.net.URL;
            7 import java.net.URLClassLoader;
            8 import java.nio.ByteBuffer;
            9 import java.security.AccessControlContext;
           10 import java.security.AccessController;
           11 import java.security.CodeSigner;
           12 import java.security.CodeSource;
           13 import java.security.PermissionCollection;
           14 import java.security.PrivilegedAction;
           15 import java.security.SecureClassLoader;
           16 import java.util.Arrays;
           17 import java.util.HashMap;
           18 import java.util.Map;
           19 import java.util.jar.Attributes;
           20 import java.util.jar.Manifest;
           21 
           22 
           23 import sun.misc.JavaNetAccess;
           24 import sun.misc.Resource;
           25 import sun.misc.SharedSecrets;
           26 import sun.misc.URLClassPath;
           27 
           28 /**
           29  * The class loader used for loading from java.class.path.
           30  * runs in a restricted security context.
           31  */
           32 public class MyClassLoader extends URLClassLoader {
           33     public URLClassPath ucp;
           34       private Map<String, Class<?>> cache = new HashMap();
           35       private static final Method defineClassNoVerifyMethod;
           36       
           37       static String[] paths = System.getProperty("java.class.path").split(";");
           38       
           39       static URL[] urls = new URL[paths.length];
           40 
           41       static{
           42           System.out.println(Arrays.toString(paths));
           43           System.out.println(System.getProperty("java.class.path"));
           44           for(int i=0; i<urls.length; i++){
           45               try {
           46                   
           47                 urls[i] = new URL("file:"+paths[paths.length-1-i]);
           48             } catch (MalformedURLException e) {
           49                 e.printStackTrace();
           50             }
           51           }
           52           System.out.println(Arrays.toString(urls));
           53         SharedSecrets.setJavaNetAccess(new JavaNetAccess() {
           54           public URLClassPath getURLClassPath(URLClassLoader u) {
           55             return ((MyClassLoader)u).ucp;
           56           } } );
           57         Method m;
           58         try {
           59           m = SecureClassLoader.class.getDeclaredMethod(
           60             "defineClassNoVerify"new Class[] { String.class
           61             ByteBuffer.class, CodeSource.class });
           62           m.setAccessible(true);
           63         } catch (NoSuchMethodException nsme) {
           64           m = null;
           65         }
           66         defineClassNoVerifyMethod = m;
           67       }
           68       
           69       public MyClassLoader(URL[] urls) {
           70             super(MyClassLoader.urls);
           71             this.ucp = new URLClassPath(MyClassLoader.urls);
           72         }
           73       
           74       public MyClassLoader(ClassLoader parent) {
           75             super(MyClassLoader.urls, parent);
           76             this.ucp = new URLClassPath(MyClassLoader.urls);
           77         }
           78 
           79       public Class<?> loadClass(String name)
           80         throws ClassNotFoundException{
           81         Class c = null;
           82         
           83         if (name.contains("hadoop")) {
           84           c = (Class)this.cache.get(name);
           85           if (c == null) {
           86             c = findClass(name);
           87             this.cache.put(name, c);
           88           }
           89         } else {
           90           c = loadClass(name, false);
           91         }
           92         return c;
           93       }
           94 
           95       protected Class<?> findClass(String name)
           96         throws ClassNotFoundException
           97       {
           98         String path = name.replace('.''/').concat(".class");
           99         Resource res = this.ucp.getResource(path);
          100         if (res != null) {
          101           try {
          102             return defineClass(name, res, true);
          103           } catch (IOException e) {
          104             throw new ClassNotFoundException(name, e);
          105           }
          106         }
          107         throw new ClassNotFoundException(name);
          108       }
          109 
          110       private Class<?> defineClass(String name, Resource res, boolean verify) throws IOException
          111       {
          112         int i = name.lastIndexOf('.');
          113         URL url = res.getCodeSourceURL();
          114         if (i != -1) {
          115           String pkgname = name.substring(0, i);
          116 
          117           Package pkg = getPackage(pkgname);
          118           Manifest man = res.getManifest();
          119           if (pkg != null)
          120           {
          121             if (pkg.isSealed())
          122             {
          123               if (!pkg.isSealed(url)) {
          124                 throw new SecurityException(
          125                   "sealing violation: package " + pkgname + 
          126                   " is sealed");
          127               }
          128 
          129             }
          130             else if ((man != null&& (isSealed(pkgname, man))) {
          131               throw new SecurityException(
          132                 "sealing violation: can't seal package " + 
          133                 pkgname + ": already loaded");
          134             }
          135 
          136           }
          137           else if (man != null)
          138             definePackage(pkgname, man, url);
          139           else {
          140             definePackage(pkgname, nullnullnullnullnullnull
          141               null);
          142           }
          143 
          144         }
          145 
          146         ByteBuffer bb = res.getByteBuffer();
          147         byte[] bytes = bb == null ? res.getBytes() : null;
          148 
          149         CodeSigner[] signers = res.getCodeSigners();
          150         CodeSource cs = new CodeSource(url, signers);
          151 
          152         if (!verify)
          153         {
          154           Object[] args = { name, bb == null ? ByteBuffer.wrap(bytes) : bb, 
          155             cs };
          156           try {
          157             return (Class)defineClassNoVerifyMethod.invoke(this, args);
          158           }
          159           catch (IllegalAccessException localIllegalAccessException) {
          160           }
          161           catch (InvocationTargetException ite) {
          162             Throwable te = ite.getTargetException();
          163             if ((te instanceof LinkageError))
          164               throw ((LinkageError)te);
          165             if ((te instanceof RuntimeException)) {
          166               throw ((RuntimeException)te);
          167             }
          168             throw new RuntimeException("Error defining class " + name, 
          169               te);
          170           }
          171 
          172         }
          173         return defineClass(name, bytes, 0, bytes.length, cs);
          174       }
          175 
          176       private boolean isSealed(String name, Manifest man) {
          177         String path = name.replace('.''/').concat("/");
          178         Attributes attr = man.getAttributes(path);
          179         String sealed = null;
          180         if (attr != null) {
          181           sealed = attr.getValue(Attributes.Name.SEALED);
          182         }
          183         if ((sealed == null&& 
          184           ((attr = man.getMainAttributes()) != null)) {
          185           sealed = attr.getValue(Attributes.Name.SEALED);
          186         }
          187 
          188         return "true".equalsIgnoreCase(sealed);
          189       }
          190 }
          191 
          注: isSealed(), defineClass(), findClass(), 都是直接從URLClassLoader復制過來.
          代碼較粗糙, 不過意思很簡單, 就是通過把java.class.path的jar包反順序, 然后定義了自己的
          Class<?> loadClass(String name) 方法, 在加載我需要的類時在已被反序的的jar包中查找, 這樣就能首先加載我修改的類了.
          運行方法:
          java -Djava.system.class.loader=org.taobao.yuling.testClassLoader.MyClassLoader -classpath ...  MyTestClass

          Feedback

          # re: 實現自定義的classLoader加載classpath中的class[未登錄]  回復  更多評論   

          2015-01-07 14:03 by 阿帕奇
          挺不錯的。、

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 会昌县| 德令哈市| 禄丰县| 东安县| 牟定县| 襄汾县| 永修县| 紫阳县| 乐清市| 长丰县| 舞阳县| 通许县| 荥经县| 大渡口区| 靖江市| 什邡市| 汉川市| 平原县| 突泉县| 霍城县| 海晏县| 通江县| 江西省| 泰顺县| 澄江县| 大渡口区| 金华市| 秦安县| 杭锦后旗| 华阴市| 长汀县| 南充市| 新营市| 庐江县| 祥云县| 陇南市| 绥滨县| 滁州市| 潮州市| 扶绥县| 宜昌市|