2009-08-19 26 views
4

我維護一個可幫助用戶將照片上傳到我們的服務的小程序。小程序jar文件有幾個.properties文件:如何在加載已經在applet jar文件中的屬性時阻止對服務器的請求?

>> jar -tf applet.jar | grep prop 
res/messages.properties 
res/messages_ca.properties 
res/messages_es.properties 
... 

小程序初始化過程中,這些被加載。

messages = ResourceBundle.getBundle("res.messages"); 

此調用但是產生4至5對服務器的請求尋找那不在jar文件中的文件,在回落至包括在.jar.properties文件之前。

從服務器錯誤日誌:

[error] File does not exist: /photos/res/messages.class 
[error] File does not exist: /photos/res/messages_en.class 
[error] File does not exist: /photos/res/messages_en.properties 
[error] File does not exist: /photos/res/messages_en_US.class 
[error] File does not exist: /photos/res/messages_en_US.properties 

ResourceManager.getBundle文檔解釋說,這是它做的方式:

的getBundle然後在候選包名稱迭代來發現第一爲此它可以實例化一個實際的資源包。對於每個候選包名稱,它試圖創建資源包:

  • 首先,它嘗試使用候選包名稱加載一個類。如果可以使用指定的類加載器找到並加載這樣的類,那麼賦值與ResourceBundle兼容,可以從ResourceBundle訪問並且可以實例化,getBundle將創建此類的新實例並將其用作結果資源包。

  • 否則,getBundle將嘗試查找屬性資源文件。它通過替換全部「。」來從候選包名中生成一個路徑名。帶有「/」的字符並附加字符串「.properties」。它嘗試使用ClassLoader.getResource查找具有此名稱的「資源」。

我肯定有很好的理由做這種方式,但對我來說,似乎浪費,我認爲應該有哪些是已知的文件五次失敗的請求不存在的服務器。

是否有任何方法教小程序只在.jar文件中查找這些文件?

注意:我不是Java程序員,所以如果有更好的方法來加載屬性比ResourceManager.getBundle,請讓我知道。

+0

什麼是您的最低Java版本? – McDowell 2009-08-19 19:41:18

+0

1.4以上是我們需要支持的。你的答案是否依賴於這些信息?無論如何請回復。如果您的解決方案對舊版本無效,那麼它仍然很有用,如果只是添加到原因列表中,我們應該停止支持1.4 :) – 2009-08-19 21:20:18

回答

5

Java 1.6引入了ResourceBundle.Control類,如果您不支持Java 1.4,可能會提供一些幫助。就你而言,編寫自己的捆綁管理器並不是火箭科學。

這個演示代碼限制包加載到屬性文件中給定的語言:

public class CustomManager { 
    private static final Map BUNDLES = new HashMap(); 

    public static ResourceBundle getBundle(String name, Set languages) { 
    Locale locale = Locale.getDefault(); 
    if (languages.contains(locale.getLanguage())) { 
     name = name + "_" + locale.getLanguage(); 
    } 
    synchronized (BUNDLES) { 
     ResourceBundle bundle = (ResourceBundle) BUNDLES.get(name); 
     if (bundle == null) { 
     ClassLoader loader = getContextClassLoader(); 
     bundle = loadBundle(loader, name.replace('.', '/') + ".properties"); 
     BUNDLES.put(name, BUNDLES); 
     } 
     return bundle; 
    } 
    } 

    private static ClassLoader getContextClassLoader() { 
    return Thread.currentThread().getContextClassLoader() != null ? Thread 
     .currentThread().getContextClassLoader() : CustomManager.class 
     .getClassLoader() != null ? CustomManager.class.getClassLoader() 
     : ClassLoader.getSystemClassLoader(); 
    } 

    private static ResourceBundle loadBundle(ClassLoader loader, String res) { 
    try { InputStream in = loader.getResourceAsStream(res); 
     try { return new PropertyResourceBundle(in); 
     } finally { in.close(); } 
    } catch (IOException e) { throw new IllegalStateException(e.toString()); } 
    } 
} 

此代碼模擬調用來檢索字符串爲西班牙/西班牙語言環境:

Set languages = new HashSet(Arrays.asList(new String[] { "es", "ca" })); 
Locale.setDefault(new Locale("es", "ES")); 
ResourceBundle bundle = CustomManager.getBundle("l10n.res.foo", languages); 
System.out.println(bundle.getString("bar")); 

由於該語言集是escaCustomManager僅支持語言(不是國家代碼或變體)只能加載以下文件:

l10n/res/foo.properties 
l10n/res/foo_es.properties 
l10n/res/foo_ca.properties 

想要獲得LocaleClassLoader支持以及想要管理語言列表的位置的複雜程度取決於您。

警告:我不會認爲我違反了實現中的任何安全限制,但我只是在桌面應用程序中測試了代碼。

+0

@McDowell:感謝您抽出寶貴時間回覆。我會嘗試這種方法。 – 2009-08-24 17:48:13

+0

感謝這個解決方案,稍微改進一下:\t \t if(languages.contains(locale.getLanguage()))name = name +「_」+ locale.getLanguage(); else if(languages.contains(locale.toString()))\t name = name +「_」+ locale.toString(); – 2013-07-31 19:09:10

+0

請注意,如果您期望您的applet使用IcedTea-Web插件,則此解決方案存在問題,但對於從Java調用Java代碼作爲Thread.currentThread()啓動的JavaScript代碼不起作用。getContextClassLoader() )'不會返回你的applet類加載器,而是一個類加載器無法加載你的資源。我的建議是堅持使用標準的'java.util.ResourceBundle#getBundle',並禁用'codebase_lookup'來防止對服務器的調用。 – 2015-05-25 19:51:45

0

Jaime Hablutzel解決方案正常工作。 很遺憾,我還沒有足夠的聲望來投票。

當您實例化小程序時,將codebase_lookup設置爲false可以準確告知類加載程序,該小程序在jar文件中部署了所有必需的類和資源,並避免了不必要的代碼庫查找。

相關問題