Как предотвратить запросы к серверу при загрузке свойств, которые уже находятся в файле jar апплета? - PullRequest
4 голосов
/ 19 августа 2009

У меня есть апплет, который помогает пользователям загружать фотографии в наш сервис. Файл апплета jar содержит несколько .properties файлов:

>> 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, а затем возвращается к файлу .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.

Я уверен, что для этого есть веские причины, но в моем случае мне кажется расточительным, что должно быть пять неудачных запросов на файлы, о которых известно, что они не существуют на сервере.

Есть ли способ научить апплет искать эти файлы только в файле .jar?

Примечание: я не программист на Java, поэтому, если есть лучший способ загрузить свойства, чем ResourceManager.getBundle, пожалуйста, сообщите мне.

Ответы [ 3 ]

6 голосов
/ 22 августа 2009

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"));

Поскольку набор языков es, а ca и CustomManager поддерживают только языки (не коды или варианты стран), могут быть загружены только следующие файлы:

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

Насколько изощренным вы хотите получить поддержку Locale и ClassLoader и где вы хотите управлять списком языков, зависит от вас.

Предупреждение: я не думаю Я нарушил все ограничения безопасности при реализации, но я только протестировал код в настольном приложении.

1 голос
/ 25 мая 2015

Просто установите для атрибута 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.

0 голосов
/ 22 июня 2015

Jaime Hablutzel Solution отлично работает. Жаль, что у меня до сих пор не хватает репутации, чтобы проголосовать.

Установка codebase_lookup в значение false, когда вы запускаете апплет, точно сообщает загрузчику классов, что апплет развернут со всеми необходимыми классами и ресурсами в файлах jar, и чтобы избежать ненужного поиска в базе кода.

...