類的加載器的各種方式總結

 水平有限,歡迎更正

類加載的原理:就是通過一個類包的全限定名來加載某個類。

至於類的加載原理及加載順序,可以上網查找,在這裏就不累述了。

類加載加載類的方式

1.      直接new 一個ClassLoader ,實現內部匿名類

要實現加載類,可以重寫loadClass方法,然後調用ClassLoader的defineClass方法;比如:

ClassLoader  myClassLoader = new ClassLoader() {

           @Override

           public Class<?> loadClass(String name) throwsClassNotFoundException{

       try {

String fileName = name.substring(name.lastIndexOf(".")+1)+".class";

InputStream is = LoadClass.class.getResourceAsStream(fileName);

                  if (is==null) {

                     return super.loadClass(name);

                  }

                  byte[] b = new byte[is.available()];

                  is.read(b);

                  return defineClass(name, b, 0, b.length);

              } catch (Exception e) {

                  throw new ClassNotFoundException(name);

              }

           }

       };

如果要想加載package下面的某個類,需要這樣寫

Object obj =myClassLoader.loadClass(PackageName+類名);

例如:myClassLoader.loadClass("feinno.proxy.entityClass."+”Flags”);

此時類加載器的結構爲

myClassLoaderà sun.misc.Launcher$AppClassLoader@1bcfbeàsun.misc.Launcher$ExtClassLoader@3f3fbd

解釋爲本類的加載器,它的父加載器爲AppClassLoader,AppClassLoader的父加載器爲ExtClassLoader。

這個加載器的加載順序是myClassLoader要加載某個類,就會請求父加載器加載,若此時父加載器也找不到,則會請求父加載器的父加載器加載,如此下去仍找不到會拋出異常ClassNotFoundException,然後自己再去嘗試加載。

2.      通過URL來加載,可以加載指定的URL下的類

String  filePath =”xxxxxxxxxx”;

URL[] urls = new URL[] {new URL(filePath)};(這個裏面可以放多個URL)

URLClassLoader ul = new URLClassLoader(urls);

Class c =ul.loadClass("feinno.proxy.entityClass"+"."+name);

這樣就可以通過指定的URL,然後通過查找整個package+name就可以找到自己要加載的類。最後ul要關閉。

3.      繼承ClassLoader ,類似方法2,也是通過URL來加載類,但是獲取類又採用方法1的形式

例如:

String filePath = “xxxxxxxxxxxxxxxxxx”;

File file = new File(filePath);

URL url = file.toURL();

URLConnection con =url.openConnection();

         InputStream is =con.getInputStream();

if (is==null) {

                            System.out.println("null");

                            getSystemClassLoader();

                   }

                   ByteArrayOutputStreambaos = new ByteArrayOutputStream();

                   bytebuf[] = new byte[1024];

                   //讀取文件流

                   for(int i = 0; (i = classIs.read(buf)) != -1; ) {

                       baos.write(buf, 0, i);

                   }

                   classIs.close();

                   baos.close();

                  

                  

                   //創建新的類對象

                   byte[]data = baos.toByteArray();

                      defineClass(name, data, 0, data.length);

4.      可以獲取到類的字節流,但是要第三方類包asm-all-3.3.1.jar,很簡單的兩句代碼就可以獲取到類的字節流,然後打印出該類變量,如下:

ClassReader reader = new ClassReader(newFileInputStream(filePath+"main/java/feinno/proxy/entityClass/"+name+".class"));

                   ClassNodecn = new ClassNode();

                  

                   reader.accept(cn,0);

           Field[]fiels=cn.getClass().getDeclaredFields();

           System.out.println("@@"+fiels.length);

           for(inti=0;i<fiels.length;i++){

                   

                    System.out.println(fiels[i]);

           }

5.      其他方法獲取類如Class.forName(“xxx”)等等,可以看jdk API文檔

6.      一般用URLClassLoader時,它的類加載結構爲java.net.URLClassLoader@13e846f,父加載器爲AppClassLoader,ExtClassLoader,null。Web工程的類加載器的結構爲WebappClassLoader,StandardClassLoader,AppClassLoader,ExtClassLoader,null(事實上是啓動類加載器,也就是啓動時的bootstrap classloader)。而上層類加載器能加載的jar包是一定的,所以一個web工程裏如果用到URLClassLoader時,很可能會包類與類轉換錯誤等,此時解決辦法就是把URLClassLoader類加載器直接定位到WebappClassLoader,然後再反射到addURL(),再把指定的URL加到URLClassLoader中,方法如下:

privatestatic Method addURL = initAddMethod();

private static  URLClassLoader classLoader = (URLClassLoader) ResolveJAR.class.getClassLoader();//爲了和把類加載器調成同一個

 

/**

     * 初始化addUrl 方法.

     * @return 可訪問addUrl方法的Method對象

     */

 privatestatic Method initAddMethod() {

        try{

           Method add = URLClassLoader.class.getDeclaredMethod("addURL",new Class[] { URL.class });

           add.setAccessible(true);

           return add;

        }

        catch(Exception e) {

           throw new RuntimeException(e);

        }

    }

           /**

     * 通過filepath加載文件到classpath

     * @paramfilePath 文件路徑

     * @returnURL

     * @throwsException 異常

     */

    privatestatic void addURL(URL url) {

        try{

           addURL.invoke(classLoader, new Object[] { url });

        }

        catch(Exception e) {

        }

    }

 

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