1. 程式人生 > >運用URLClassLoader載入外部jar包的java類,生成Class檔案

運用URLClassLoader載入外部jar包的java類,生成Class檔案

先來一段網上copy的話術:

      //****************************

很多時候 我們寫的java程式是分模組的,有很好的擴充套件機制,即我們可以為我們自己的java類新增外掛,來執行將來某天我們可能開發出來的類,以下稱這些類為外掛類。

下邊是一種簡單的實現方法:

Class A 作為程式的主入口,其中包含了程式的執行入口(main)函式。然後在main函式中通過外部的配置檔案,然後通過外部的配置檔案,我們可以獲得外掛類的資訊(位於哪個jar包,jar包的具體路徑),然後獲得jar包中某一個類的例項,來完成相應的工作。這個jar包很可能是外部的jar包,是我們自己寫好的,那麼我們放到哪裡,他才能自己找到呢?我嘗試過很多次,除非將其具體目錄,放到class_path中才可以成功執行,否則報的異常只有一個ClassNotFoundException,就是找不到類。不過還有一種方法,就是將該jar包解壓到執行jar包所在的目錄,這樣就可以通過class_path中的.來獲得相應的類了。不過這樣會顯得很不專業,java寫出來的東西都是jar包啊,自己感覺的。放到claspath中,不能每次寫出新的jar包都配置一遍吧!

如此出現瞭如下的解決辦法:

想了解解決辦法的含義,首先要了解java的類載入機制。眾所周知,程式若想執行,必須載入到記憶體當中才能成功執行。java程式並不是可執行檔案,由許多獨立的類檔案來完成。所以java中載入程式是以類為單外來完成的。這也就需要我們來簡單瞭解一下java的class loader載入機制。

java程式開始執行,遇到的第一個classloader是bootstrap classloader,這個classloader是用c++語言編寫,通過他來完成載入java中的核心類。第二個classloader是extension classloader,載入的是jre/lib目錄中的ext目錄中的jar包。然後第三個是system classloader,也被稱為應用載入器,主要負責完成載入-classpath 或者系統中的全域性變數ClassPath中的類。System.out.println(System.getProperty(“java.class.path”));可以獲得classpath的配置,也就是system classloader 載入的類,第四個class loader可能是使用者自定義的載入器,來自定義載入類。通常一個類的載入過程是這樣的通過當前的類載入器的父載入器嘗試查詢,如果沒有再找其父載入器嘗試載入,直到最終的bootstrap classloader為止,如果還沒有找到,那麼就開始從上往下載入類。這樣做的目的是防止自定義的類來覆蓋系統中的類,如果沒有這種機制很容易出現這種笑話,自己寫了一個String類,然後new string的時候是自己寫的String類,這樣就比較好玩了。

//*********************************************

    下面是我最近做專案的實際程式碼,可以作為參考:

1.自己定義URLClassLoader物件載入外部jar包,針對jar包裡面不再出現別的jar包的情況,即只解析.class檔案:

  1. privatestaticvoid test1() {  
  2.  String path = "D:\\test.jar";//外部jar包的路徑
  3.  Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
    //所有的Class物件
  4.  Map<Class<?>, Annotation[]> classAnnotationMap = new HashMap<Class<?>, Annotation[]>();//每個Class物件上的註釋物件
  5.  Map<Class<?>, Map<Method, Annotation[]>> classMethodAnnoMap = new HashMap<Class<?>, Map<Method,Annotation[]>>();//每個Class物件中每個方法上的註釋物件
  6.  try {  
  7.   JarFile jarFile = new JarFile(new File(path));  
  8.   URL url = new URL("file:" + path);  
  9.   ClassLoader loader = new URLClassLoader(new URL[]{url});//自己定義的classLoader類,把外部路徑也加到load路徑裡,使系統去該路經load物件
  10.   Enumeration<JarEntry> es = jarFile.entries();  
  11.   while (es.hasMoreElements()) {  
  12.    JarEntry jarEntry = (JarEntry) es.nextElement();  
  13.    String name = jarEntry.getName();  
  14.    if(name != null && name.endsWith(".class")){//只解析了.class檔案,沒有解析裡面的jar包
  15.     //預設去系統已經定義的路徑查詢物件,針對外部jar包不能用
  16.     //Class<?> c = Thread.currentThread().getContextClassLoader().loadClass(name.replace("/", ".").substring(0,name.length() - 6));
  17.     Class<?> c = loader.loadClass(name.replace("/"".").substring(0,name.length() - 6));//自己定義的loader路徑可以找到
  18.     System.out.println(c);  
  19.     classes.add(c);  
  20.     Annotation[] classAnnos = c.getDeclaredAnnotations();  
  21.     classAnnotationMap.put(c, classAnnos);  
  22.     Method[] classMethods = c.getDeclaredMethods();  
  23.     Map<Method, Annotation[]> methodAnnoMap = new HashMap<Method, Annotation[]>();  
  24.     for(int i = 0;i<classMethods.length;i++){  
  25.      Annotation[] a = classMethods[i].getDeclaredAnnotations();  
  26.      methodAnnoMap.put(classMethods[i], a);  
  27.     }  
  28.     classMethodAnnoMap.put(c, methodAnnoMap);  
  29.    }  
  30.   }  
  31.   System.out.println(classes.size());  
  32.  } catch (IOException e) {  
  33.   e.printStackTrace();  
  34.  } catch (ClassNotFoundException e) {  
  35.   e.printStackTrace();  
  36.  }  
  37. }  

以上的這種情況可以在別的project專案裡寫test方法,是平時最常用的,如果當.class檔案裡有依賴別的jar包裡的物件的時候,就要把該jar包拷貝到寫此測試方法的project並buildPath,不然的話執行的時候會報找不到Class物件的異常。

2.第二種情況是針對載入jar包裡面的jar包的Class物件,還有讀取某一個properties檔案的方法。

  1. privatestaticvoid test2() {  
  2.   String path = "D:\\test.jar";//此jar包裡還有別的jar包
  3.   try {  
  4.    JarFile jarfile = new JarFile(new File(path));  
  5.    Enumeration<JarEntry> es = jarfile.entries();  
  6.    while (es.hasMoreElements()) {  
  7.     JarEntry je = es.nextElement();  
  8.     String name = je.getName();  
  9.     if(name.endsWith(".jar")){//讀取jar包裡的jar包
  10.      File f = new File(name);  
  11.      JarFile j = new JarFile(f);  
  12.      Enumeration<JarEntry> e = j.entries();  
  13.      while (e.hasMoreElements()) {  
  14.       JarEntry jarEntry = (JarEntry) e.nextElement();  
  15.       System.out.println(jarEntry.getName());  
  16.       //.........接下去和上面的方法類似
  17.      }  
  18.     }  
  19. //    System.out.println(je.getName());
  20.     if(je.getName().equals("entity_pk.properties")){  
  21.      InputStream inputStream = jarfile.getInputStream(je);  
  22.      Properties properties = new Properties();  
  23.      properties.load(inputStream);  
  24.      Iterator<Object> ite = properties.keySet().iterator();  
  25.      while (ite.hasNext()) {  
  26.       Object key = ite.next();  
  27.       System.out.println(key + " : " +properties.get(key));  
  28.      }  
  29.     }  
  30.    }  
  31.   } catch (IOException e) {  
  32.    e.printStackTrace();  
  33.   }  
  34.  }  

3.第三種情況是在該專案下獲取某個包的Class物件,當然了,測試方法是在該專案下寫的(這樣classLoader就直接可以知道物件了,不需要再自定義URLClassLoader了,用Thread.currentThread().getContextClassLoader().loadClass(.....)就可以直接獲得Class物件了,回去ClassPath下找,System.out.print(System.getProperty("java.class.path"))就可以找到classPath路徑)。

  1. privatestatic Set<Class<?>>  getclass() {  
  2.   Set<Class<?>> classes = new LinkedHashSet<Class<?>>();  
  3.   boolean flag = true;//是否迴圈迭代
  4.   String packName = "com.yk.framework.db";  
  5. //  String packName = "org.jdom";
  6.   String packDir = packName.replace(".""/");  
  7.   Enumeration<URL> dir;  
  8.   try {  
  9.    dir = Thread.currentThread().getContextClassLoader().getResources(packDir);  
  10.    while(dir.hasMoreElements()){  
  11.     URL url = dir.nextElement();  
  12.     System.out.println("url:***" + url);  
  13.     String protocol = url.getProtocol();//獲得協議號
  14.     if("file".equals(protocol)){  
  15.      System.err.println("file型別的掃描");  
  16.      String filePath = URLDecoder.decode(url.getFile(), "UTF-8");  
  17.      System.out.println("filePath :" + filePath);  
  18.      findAndAddClassesInPackageByFile(packName, filePath,flag,classes);  
  19.     }elseif("jar".equals(protocol)){  
  20.      System.err.println("jar型別掃描");  
  21.      JarFile jar;  
  22.      jar = ((JarURLConnection)url.openConnection()).getJarFile();  
  23.      Enumeration<JarEntry> entries = jar.entries();  
  24.      while(entries.hasMoreElements()){  
  25.       JarEntry entry = entries.nextElement();  
  26.       String name = entry.getName();  
  27.       System.out.println(">>>>:" + name);  
  28.       //......
  29.      }  
  30.     }  
  31.    }  
  32.   } catch (IOException e) {  
  33. 相關推薦

    運用URLClassLoader載入外部jarjava生成Class檔案

    先來一段網上copy的話術:       //**************************** 很多時候 我們寫的java程式是分模組的,有很好的擴充套件機制,即我們可以為我們自己的java類新增外掛,來執行將來某天我們可能開發出來的類,以下稱這些

    Java動態載入器(載入外部jar 讀取資原始檔)

    Code: package xx.xx.xx import java.io.IOException; import java.io.InputStream; import java.util.jar.JarEntry; import java.util.jar.JarFi

    使用java.lang.instrument實現第三方jar的修改包括引入外部依賴引數獲取

    最近專案開發需求中,使用了第三方供應商提供的jar包形式的sdk ,sdk中的日誌由其自己管理列印,現在想獲取到日誌列印時傳入的message,就必須想辦法對sdk的原始碼進行改動。 首先想到的是反編譯jar包,然後修改後重新打包,嘗試了一下後感覺很麻煩,而且很不cool。

    Tomcat專案執行時載入jar檔案的順序

    tomcat的載入執行機制與Java虛擬機器的父類委託機制稍有不同。 下面來做詳細敘述: 1、首先載入Tomcat_HOME/lib目錄下的jar包 2、然後載入Tomcat_HOME/webapps/專案名/WEB-INF/lib的jar包 3、最後載

    linux伺服器上執行java程式,引用外部jar

     將寫好的java程式放到Linux上執行,可以利用Linux伺服器更快的跑完程式。由於我windows和linux下使用的jdk版本不同,因此將windows的java程式打成jar包後在linux下執行總會報錯。於是只能在Linux下使用javac命令編譯生成class

    android專案匯入外部jar後不報錯但執行時報找不到的問題

    解決辦法:一、 在專案右鍵--> Build Path --> Configure Build Path --> 在Libraries tab中 點選右邊的Add Library--> User Libraries --> New --> 輸入你的Library名字,確定

    Java Web】Myeclipse下運用maven管理專案jar

     Java Web開發的人都知道經常會為缺少各種jar包而煩惱,經常要去各種地方下載。用maven來管理專案的jar包,就非常方便了,maven會自動幫你下載所需要的各種jar包。  下面就來介紹一下

    將eclipse java程式打包成jar的總結(包括工程中沒有引用外部jar和有引用外部jar兩種情況)

    一.當eclispe java工程中沒有引用外部jar包時: 選中工程---->右鍵,Export...--->Java--->JAR file--->next-->填寫jar file的路徑及名稱-->next-->next-

    使用java命令列執行依賴外部jarclass檔案

    很久沒用java的命令列來執行class了,今天拾回來這個,特此記錄  -Djava.ext.dirs=/wd/tomcat6/webapps/wcity/WEB-INF/lib/ 是class依賴的jar包的路徑 java -Djava.ext.dirs=/wd/tomc

    怎樣把java工程打成jar--連帶外部jar

    1、使用eclipse的export。生成一個jar包,指定程式的入口的class。 2、因為使用export不會把外部的jar包,一同打包。所以要進行如下操作:      1)比如在/root/下新建資料夾test      2)把1生成的jar包,拷到test目錄

    javax jar常用

    res int request let response req interface quest pub 1.public interface HttpServletRequest extends ServletRequest 都在package javax.servle

    IntelliJ IDEA 10.5.1 引用外部Jar

    jar tac att ide dea 引用 int structure nbsp 具體步驟: File -> Project Structure (ctrl + shift + alt + s ) -> Module -> Dependencies -&

    maven 引入外部jar的幾種方式

    dep repo 執行 install tor 顯式 pat comment osi 方式1:dependency 本地jar包 <dependency> <groupId>com.hope.cloud</groupId

    關於Maven項目引入外部jar的方式

    jar tid sim dos .cn pos xxx pack src 在項目中有時候需要引入一些外部jar包,這些jar從中央倉庫是找不到的,如果是普通web工程直接將jar放在WEN-INF\lib下再add build to path就行了,但是maven項目這麽

    RXTXcommon.jar的匯入Java串列埠

                                              &nb

    使用groovy指令碼使gradle靈活載入本地jar的兩種方式

    本人在使用Jenkins做測試專案的可持續整合過程中,構建工具用的gradle,但由於一些jar包是並私有倉庫給用,暫時沒有搭建計劃。這就導致了我構建專案的時候需要的jar的地址往往是不一樣的,而且伺服器和本地的版本可能也有所差別,經常其他同學提交程式碼時候把build.gradle檔案一併提交了,

    動態web專案Libraries下沒有Web App Libraries(自然這裡面也不會有Web-INF的lib下載入jar)資料夾~

    動態web專案Libraries下沒有Web App Libraries(自然這裡面也不會有Web-INF的lib下載入的jar包)資料夾,無法載入需要使用的jar包的時候,開啟(D:\workspace\aosp\.settings)org.eclipse.wst.common.component

    [Java] Jar2Exe,jar2工具將jar轉換成exe可執行檔案的詳細過程

    [Java] Jar2Exe,jar2工具將jar包轉換成exe可執行檔案的詳細過程 軟體下載地址 連結: https://pan.baidu.com/s/1Ei39JYGpb7wyS9UkMl1GTQ 提取碼: yvkv 一、首先將程式匯出為jar包 1、在MyEcli

    Android-0.eclipse中匯入外部jar

    eclipse匯入外部jar包 0.把第三方jar檔案放在本專案中 在專案名上右擊,依次點選【New】-->【Source Floder】,開啟新建資料夾視窗 輸入資料夾名稱【lib】,點選【ok】。我們通常在lib資料夾中存放從外部引入的jar包

    javajar、excel、txt等檔案儲存於mysql

    首先要注意mysql的欄位型別,可以選擇BLOB型別或text型別,這兩種型別是進行儲存檔案位元組碼的型別; 具體使​​​​​​​用要根據傳入的檔案的大小限制,這裡我們是不能大於16M,所以這裡使用的是 mediumtext型別的欄位; 本次通過儲存檔案的Base64字串