java自定義類加載器

前言

  java反射,最常用的Class.forName()方法。做畢設的時候,接收到代碼字符串,通過 JavaCompiler將代碼字符串生成A.class文件(存放在classpath下,也就是eclipse項目中的bin目錄里),然后通過java反射機制,獲取main方法并執行。.class文件名稱固定。當 A.class文件更新的時候,問題出現了,main方法的執行結果總和第一次的執行結果相同。

程序流程

  代碼提交->接收代碼->編譯成A.class文件->java反射->main方法執行

  具體代碼參考:http://www.cnblogs.com/hujunzheng/p/5203067.html

問題原因

  類加載器的委托機制!說到這里,不得不介紹一下java的類加載器。

java虛擬機中的類加載器

  java虛擬機中可以安裝多個類加載器,系統默認三個主要的類加載器,每個類負責加載特定位置的類: BootStrap,ExtClassLoader,AppClassLoader

  類加載器也是Java類,因為Java類的類加載器本身也是要被類加載器加載的,顯然必須有第一個類加載器不是Java類,這個正是BootStrap,使用C/C++代碼寫的,已經封裝到JVM內核中了,而ExtClassLoader和AppClassLoader是Java類。

類加載器的屬性結構圖

  盜圖一張:

由此得到結論

  首先我的A.class文件更新了,接著調用Class.forName()[我想的是重新加載一下字節碼文件對象],然后最終由AppClassLoader去加載,其中有一個函數很重要,就是loadClass(), 看一下這個函數的源碼,如下:

protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{  //加上鎖,同步處理,因為可能是多線程在加載類  synchronized (getClassLoadingLock(name)) {  //檢查,是否該類已經加載過了,如果加載過了,就不加載了  Class c = findLoadedClass(name);  if (c == null) {  long t0 = System.nanoTime();  try {  //如果自定義的類加載器的parent不為null,就調用parent的loadClass進行加載類  if (parent != null) {  c = parent.loadClass(name, false);  } else {  //如果自定義的類加載器的parent為null,就調用findBootstrapClass方法查找類,就是Bootstrap類加載器  c = findBootstrapClassOrNull(name);  }  } catch (ClassNotFoundException e) {  // ClassNotFoundException thrown if class not found  // from the non-null parent class loader  
         }  if (c == null) {  // If still not found, then invoke findClass in order  // to find the class.  long t1 = System.nanoTime();  //如果parent加載類失敗,就調用自己的findClass方法進行類加載  c = findClass(name);  // this is the defining class loader; record the stats  sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);  sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);  sun.misc.PerfCounter.getFindClasses().increment();  }  }  if (resolve) {  resolveClass(c);  }  return c;  }  
}  

  如果同名的.class文件之前加載了就不會在加載了。。。

解決辦法  用戶自定義類加載器

  想法1: 重寫loadClass()這個函數,無論是否加載過.class問價,都重新加載。

   @Overridepublic java.lang.Class<?> loadClass(String name) throws ClassNotFoundException {System.out.println(name);byte[] data = loaderClassData(name);return this.defineClass(name, data, 0, data.length);};

  但是竟然出錯了,至今還沒有搞明白... Main是我要加載的類,loadClass()函數執行了兩次,第二次不知道怎么調用的。。。?有誰知到,告訴我一下,謝了!

Main
java.lang.Object
java.io.FileNotFoundException: java\lang\Object.class (系統找不到指定的路徑。)at java.io.FileInputStream.open(Native Method)at java.io.FileInputStream.<init>(Unknown Source)at com.ds.tools.MyClassLoader.loaderClassData(MyClassLoader.java:53)at com.ds.tools.MyClassLoader.loadClass(MyClassLoader.java:78)at java.lang.ClassLoader.defineClass1(Native Method)at java.lang.ClassLoader.defineClassCond(Unknown Source)at java.lang.ClassLoader.defineClass(Unknown Source)at java.lang.ClassLoader.defineClass(Unknown Source)at com.ds.tools.MyClassLoader.loadClass(MyClassLoader.java:79)at com.ds.tools.MyClassLoader.main(MyClassLoader.java:96)

  想法2: 只能默默的重寫findClass()方法了, loadClass()方法中會調用這個函數,為了避過AppClassLoader檢查類是否已經加載過了,我把A.class的生成位置放到了項目根目錄下的myClass目錄中,這樣MyClassLoader委托AppClassLoader對A.class進行加載時,在當前的classpath下找不到對應的類,無法完成類的加載(同樣BootStrapLoader和ExtClassLoader都不會找到),最終是我們自定的類加載器完成類的加載,代碼如下:

public class MyClassLoader extends ClassLoader {//類加載器名稱private String loaderName;//加載類的路徑private String path = "";private final String fileType = ".class";public MyClassLoader(String loaderName){//讓系統類加載器成為該 類加載器的父加載器super();this.loaderName = loaderName;}public MyClassLoader(ClassLoader parent, String loaderName){//顯示指定該類加載器的父加載器super(parent);this.loaderName = loaderName;}public String getPath() {return path;}public void setPath(String path) {this.path = path;}@Overridepublic String toString() {return this.loaderName;}/*** 獲取.class文件的字節數組* @param name* @return*/private byte[] loaderClassData(String name){InputStream is = null;byte[] data = null;ByteArrayOutputStream baos = new ByteArrayOutputStream();name = name.replace(".", "/");try {is = new FileInputStream(new File(path + name + fileType));int c = 0;while(-1 != (c = is.read())){baos.write(c);}data = baos.toByteArray();} catch (Exception e) {e.printStackTrace();} finally{try {if(is != null)is.close();if(baos != null)baos.close();} catch (IOException e) {e.printStackTrace();}}return data;}/*** 獲取Class對象*/@Overridepublic Class<?> findClass(String name) throws ClassNotFoundException{byte[] data = loaderClassData(name);return this.defineClass(name, data, 0, data.length);}public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {for(int i=0; i<5; i++){MyClassLoader loader1 = new MyClassLoader("MyClassLoader");//String path = new File(MyClassLoader.getSystemClassLoader().getResource("").getPath()).getParent();loader1.setPath("myClass/");Class<?> clazz = loader1.loadClass("Main");System.out.println(clazz.getName());}}
}

?

轉載于:https://www.cnblogs.com/hujunzheng/p/5357008.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/531328.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/531328.shtml
英文地址,請注明出處:http://en.pswp.cn/news/531328.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

常用網址

MDN : 一個不錯的前端學習網站 https://developer.mozilla.org/zh-CN/  https://developer.mozilla.org/en-US/ CodePen 是一個網站前端設計開發平臺&#xff0c;是一個針對網站前端代碼設計的開發工具。 RunJS - 在線編輯、展示、分享、交流你的 JavaScript 代碼 : http://r…

repo介紹(一)

repo簡介 Repo 是我們以 Git 為基礎構建的代碼庫管理工具,可以組織多個倉庫的上傳和下載。它是由一系列的Python腳本組成&#xff0c;封裝了一系列的Git命令&#xff0c;用來統一管理多個Git倉庫 一個大型的項目可能由很多小的倉庫組合而成的&#xff0c;為了方便統一管理各個…

hash長度擴展攻擊

作為一個信息安全的人&#xff0c;打各個學校的CTF比賽是比較重要的&#xff01; 最近一個朋友發了道題目過來&#xff0c;發現有道題目比較有意思&#xff0c;這里跟大家分享下 這串代碼的大致意思是&#xff1a; 這段代碼首先引入了一個名為"flag.php"的文件&am…

repo介紹(二)

這篇文章來實例操作 安裝repo&#xff0c;參考repo介紹這一節創建repo存放default.xml 的git倉庫 初始化repo&#xff0c;repo init -u https://gitee.com/angerial/repo-test.git 這個時候會在當前目錄生成如下文件 參考repo組成&#xff0c;修改.repo/manifest.xml,這里我的…

springmvc環境搭建以及常見問題解決

1.新建maven工程 a) 打開eclipse&#xff0c;file->new->project->Maven->Maven Project b) 下一步 c) 選擇創建的工程為webapp&#xff0c;下一步 d) 填寫項目的group id和artifact id。一般情況下&#xff0c;group id寫域名的倒序&#xff0c;artifact id…

eclipse build workspace太慢或者 js出錯問題解決

1.js文件錯誤解決辦法 右鍵項目->properties->Builders(注&#xff1a;JavaScript Validator也會引起 build workspace太慢) 2.Eclipse 一直不停 building workspace完美解決總結&#xff08;來自: http://blog.163.com/shadow_wolf/blog/static/18346909720145279519222…

HttpUrlConnection發送url請求(后臺springmvc)

1.HttpURLConnection發送url請求 public class JavaRequest {private static final String BASE_URL "http://localhost:8080/dsdemo/";public static String userToken null;public static String problemName null;public static String sendPost(String sufUrl…

springmvc+jpa實現分頁的兩種方式

1.工具類 public final class QueryTool {public static PageRequest buildPageRequest(int pageNumber, int pageSize, String sortType){Sort sort null;if("auto".equals(sortType)) {sort new Sort(Direction.DESC, "ctime");} else {sort new Sort…

不使用session,借助redis實現驗證碼

1.首先看一下基本的流程 2.看一下代碼 注&#xff1a;其中用到的一些工具類&#xff0c;可以到我的github上去下載 https://github.com/hjzgg/usually_util/tree/master/utils windows 下的 redis下載 https://github.com/hjzgg/redis 獲取驗證碼的tooken RequestMapping(value…

PS批處理的使用

一、 前言 做開發的時候&#xff0c;最多的時候就是圖片的使用了。有時候圖片的處理都按照同樣的步驟&#xff0c;比如說統一將圖片的大小調整為固定大小&#xff0c;或者統一在所有的圖片的的某個位置上加入文字或者小圖片等等&#xff0c;這時候PS的批處理可以幫你完成這些重…

exe4j的使用

下載&#xff1a;http://download.cnet.com/exe4j/3000-2070_4-144405.html 參考&#xff1a;http://blog.chinaunix.net/uid-25749806-id-4380850.html 注&#xff1a;打包成jar包的一般就是src目錄&#xff0c;其他目錄放到目標文件夾中&#xff0c;目錄結構如下 如何解決exe…

c語言指針和數組的聯系

c語言指針與數組**一、指針與一維數組**1.一維數組的存儲方式2. 對一維數組名的理解3. 數組下標和指針的關系4.一位數組名與取數組首地址的區別**二、指針與二維數組**1.二維數組的存儲方式2.二維數組下標和指針的對應關系例題:懷著忐忑的心情寫了人生第一篇博客......誠惶誠恐…

android模擬器默認位置的修改

1.創建ANDROID_SDK_HOME環境變量&#xff0c;如ANDROID_SDK_HOMED:\eclipse_android\android-sdk 2.在ANDROID_SDK_HOME目錄下&#xff0c;建立.android目錄 3.默認的avd路徑是C:\Users\Administrator\.android, 將里面的內容放入到ANDROID_SDK_HOME中的.android目錄下 4.windo…

python 求出4行5列的二維數組周邊元素之和

題目:求出4行5列的二維數組周邊元素之和 代碼&#xff1a; import random x [[random.randint(1,10)for j in range(5)]for i in range(4)] for item in x:print(item) y [x[0][0],x[0][1],x[0][2],x[0][3],x[0][4],x[1][0],x[1][4],x[2][0],x[2][4],x[3][0],x[3][4]] prin…

android表白app

一、前言 馬上就要520和521了&#xff0c;是不是還有像我一樣的單身狗啊。我就知道有&#xff0c;所以這兩天簡單寫了這個小程序&#xff08;其實是替別人寫的&#xff09;&#xff0c;雖然我并不會用去騙女孩子&#xff08;因為最近太忙了&#xff0c;實習完之后要搞畢設&…

c語言:malloc函數的簡介

文章目錄一、為什么需要malloc函數&#xff1f;二、如何使用malloc函數&#xff1f;三、用malloc函數自定義數組長度一、為什么需要malloc函數&#xff1f; 用于解決傳統數組以下缺點。 ①傳統數組的長度必須要事先指定。 ②傳統數組的內存無法手動釋放。 ③傳統數組的長度定義…

webpack+react+es6開發模式

一、前言 實習了兩個月&#xff0c;把在公司用到的前端開發模式做個簡單的整理。公司里前端開發模式webpackreactreduxes6&#xff0c;這里去掉了redux。 webpack, react, redux等學習網址&#xff1a;http://www.cnblogs.com/hujunzheng/p/5405780.html 二、簡單的步驟條組件 …

c語言輸入字符時控制符%c前加空格的原因解釋

文章目錄一、前景知識1、緩沖區2、標準輸入流二、scanf語句的執行1、scanf對于整形%d的輸入2、scanf對于字符%c的輸入在編一個代碼時偶然間發現一個知識盲點…用scanf語句輸入字符時需要在控制符%c前加空格。在解釋相關這個原因前我們需要了解幾個相關知識點。 一、前景知識 1…

git命令分類圖

轉載于:https://www.cnblogs.com/hujunzheng/p/5560826.html

python中為什么沒有自增或者自減

在c語言和c中我們經常會用到自增或者自減的語句&#xff0c;但對于python中如果運用這種格式便會報錯…why&#xff1f; 一、預備知識 小整數池 python中為了提高儲存效率&#xff0c;對于int類型的整型變量的儲存&#xff0c;有一個專門的小整數池&#xff0c;它會存放-5到256…