如何在加载applet jar文件中已有的属性时阻止对服务器的请求?

时间:2009-08-19 18:56:38

标签: java properties jar applet

我维护了一个applet,可以帮助用户将照片上传到我们的服务中。小程序jar文件包含几个.properties个文件:

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

这些是在applet初始化期间加载的。

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

然后,此回调会向服务器生成4到5个请求,以查找不在jar文件中的文件,然后再回到.properties中包含的.jar文件

从服务器错误日志:

[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找到具有此名称的“资源”。

  •   

我确信有充分的理由这样做,但在我的情况下,对于我来说,对于已知在服务器上不存在的文件应该有五个失败的请求似乎是浪费。

有没有办法让applet只在.jar文件中查找这些文件?

注意:我不是Java程序员,所以如果有更好的方法来加载属性而不是ResourceManager.getBundle,请告诉我。

3 个答案:

答案 0 :(得分:6)

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支持以及您希望管理语言列表的位置获得的复杂程度取决于您。

警告:我没有认为我违反了实施的任何安全限制,但我只在桌面应用程序中测试了代码。

答案 1 :(得分:1)

只需在codebase_lookup代码配置中将false属性设置为<applet>,您的小程序就不会对服务器进行任何额外的资源调用(例如i18n资源包)

<applet codebase_lookup="false" ...

有关http://docs.oracle.com/javase/6/docs/technotes/guides/plugin/developer_guide/special_attributes.html#codebase的更多详情。

答案 2 :(得分:0)

Jaime Hablutzel解决方案运行良好。 遗憾的是,我仍然没有足够的声誉来投票。

当您实例化applet时,将codebase_lookup设置为false会严格告诉类加载器applet与jar文件中所有需要的类和资源一起部署,以避免不必要的代码库查找。