2010-03-18 56 views
4

我開發一個Web應用程序。負載類不是動態的Web應用程序的類路徑 - 不使用自定義類加載

  1. Web應用程序在運行中產生的Java類。例如,它生成類com.people.Customer.java
  2. 在我的代碼,我動態編譯這讓com.people.Customer.class並將其存儲在某個目錄說repository/com/people/Customer.class這是不是我的應用server.My應用程序服務器的類路徑中(我使用WebSphere Application Server/Apache Tomcat等)從WEB-INF/classes目錄獲取類。類加載器將使用它來加載類。
  3. 編譯完成後,我需要加載這個類,以便它在創建後可以被其他類使用。
  4. 當我使用Thread.currentThread().getContextClassLoader().loadClass(com.people.Customer)明顯的類加載器無法加載類,因爲它不是在類路徑中(不WEB-INF/classes)。由於類似的原因,getResource(..)getResourceAsStream(..)也不起作用。

我需要一種方法來:

閱讀類Customer.class也許作爲一個流(或任何其他方式會做),然後加載它。以下是約束:

  1. 我無法將存儲庫文件夾添加到WEB-INF/classes文件夾。
  2. 我無法創建新的自定義ClassLoader。如果我創建了一個新的ClassLoader,並且這會加載該類,那麼它的父類ClassLoader將無法訪問它。

是否有實現這一目標的方法嗎?

如果不是這樣,在最壞的情況下,有一個自定義類加載器的Web應用程序的同一類應該被用來在我的web應用程序的整個生命週期內加載應用程序覆蓋了默認的類加載器的方式。

欣賞任何解決方案:)

+1

爲什麼不能將它添加到WEB-INF/classes文件夾中?這是真正的解決方案。在任何情況下「不會」或「不會」或「寧願不」? – duffymo 2010-03-18 22:32:48

+0

@duffymo:你的假設是web應用程序部署在擴展模式,並且web應用程序具有對文件系統的寫入權限。在生產環境中情況並非總是如此。將文件寫入WEB-INF/classes不是一個好的解決方案 – mhaller 2010-03-18 22:39:42

+1

不,我不假設任何 - 你的透視界面已經關閉了,mhaller。我爭辯說WAR應該重新包裝,以包含所有必需的.class文件並重新部署。我希望看到這樣一個用例,它有必要創建一些和客戶一樣明顯的東西。實例?是。類?不,我不買它。 – duffymo 2010-03-18 23:14:15

回答

1

簡短的回答:沒有

如果沒有定製的ClassLoader,你不能動態加載的類。

但是,你,你不能使用定製的ClassLoader,因爲你在Web應用程序的ClassLoader加載的其他對象將無法使用這些新加載的類假設是不正確。所有你需要的是使用這些新創建的類的通用方法 - 就像通用接口或元描述(用於訪問bean屬性的Beans Introspector)。

但是,如果你使用第三方庫,例如Hibernate和你動態加載在運行時將被持久化的實體,那麼你將有一個困難時期,但恕我直言,這是可能的。

1

當然,你可以做到這一點。只需獲得web classloader並使用反射調用defineClass()方法(它是受保護的,所以一定要在方法上調用setAccessible(true)。defineClass()需要一個字節數組,所以它沒有任何區別。確保類名是唯一的,並且只加載一次,否則會出現複雜的類加載問題。

+0

你的解決方案是好的,但網絡類加載器不同於environement到另一個,這將使我的代碼不可移植。 – 2011-03-06 15:44:31

+0

不,它不會。 defineClass()是所有類加載器之間共享的ClassLoader方法。 – 2011-03-11 09:13:18

2

你需要一個自定義的類裝載器要做到這一點,並在這個類加載器,你需要重新定義一個方法findClass(String name)

一個例子:從

public class CustomClassLoader extends ClassLoader { 

    final String basePath = "/your/base/path/to/directory/named/repository/"; 

    @Override 
    protected Class<?> findClass(final String name) throws ClassNotFoundException { 
     String fullName = name.replace('.', '/'); 
     fullName += ".class"; 

     String path = basePath + fullName ; 
     try { 
      FileInputStream fis = new FileInputStream(path); 
      byte[] data = new byte[fis.available()]; 
      fis.read(data); 
      Class<?> res = defineClass(name, data, 0, data.length); 
      fis.close(); 

      return res; 
     } catch(Exception e) { 
      return super.findClass(name); 
     } 
    } 
} 

然後,你就可以加載類自定義位置。例如:

Class<?> clazz = Class.forName("my.pretty.Clazz", true, new CustomClassLoader()); 
Object obj = clazz.newInstance(); 

這樣做,你告訴JVM應該由你的自定義類裝載器,它知道如何其中加載自定義類加載名爲my.pretty.Clazz該類。 它解決了完整的類名稱(如my.pretty.Clazz)到文件名(在我們的例子:/your/base/path/to/directory/named/repository/my/pretty/Clazz.class),則獲得的負載資源作爲一個字節數組,最後將這個數組到一個Class實例。

這個例子非常簡單,演示了一個關於如何加載自定義類的通用技術。 我建議你閱讀一些關於課程加載的文章,例如this one