Ответ 1
ResourceBundle.clearCache();
ИЛИ
Messages_en .clearCache();
Вызов этого метода перезагрузит ресурсы, он обновит пакет
У меня есть пакет ресурсов как класс Java, который считывает значения из базы данных. Когда я обновляю db, мне нужно перезагрузить пакет, но я не знаю, как это сделать. Кто-нибудь помогает?
package model.helpers;
public class Messages_en extends ListResourceBundle {
protected Object[][] getContents() {
// from DB
// ...
}
}
В поле зрения я использую пакет, как показано ниже:
<f:loadBundle basename="model.helpers.Messages" var="m" />
ResourceBundle.clearCache();
ИЛИ
Messages_en .clearCache();
Вызов этого метода перезагрузит ресурсы, он обновит пакет
Это не совсем тривиально.
Для простое удаление ResourceBundle
через clearCache()
не всегда дает желаемые результаты. Часто вам нужно, по крайней мере, также попытаться очистить загрузчик контекстного класса:
ResourceBundle.clearCache(Thread.currentThread().getContextClassLoader());
Однако это все равно не перезагрузит пакет ресурсов, определенный в файле faces-config.xml. По крайней мере, реализация Mojarra JSF 1.2 конфиденциально кэширует пакет ресурсов внутри компании. Это происходит в:
FacesContext -> Application -> associate (ApplicationAssociate) -> resourceBundles (Map<String, ApplicationResourceBundle>()) -> resources (Map<Locale, ResourceBundle>)
Можно очистить этот кеш через отражение (в конце дня это всего лишь запись на карте), или вы можете заменить приложение. Оба - это не то, что вы обычно делаете беззаботно.
Чисто для развития вы могли бы использовать JRebel, который, вероятно, уже знает Mojarra и, скорее всего, делает трюк с отражением, упомянутый выше.
После некоторых экспериментов я пришел к следующему коду, который делает трюк на JBoss AS 5/JSF 1.2. Он привязывает ваш код к Mojarra (импортирует пакеты солнца) и может сломаться при любом обновлении из-за использования рефлексивных трюков. Но в любом случае это код:
public static void reloadBundle() {
ResourceBundle.clearCache(Thread.currentThread().getContextClassLoader());
ApplicationResourceBundle appBundle = ApplicationAssociate.getCurrentInstance().getResourceBundles().get("your_bundle_name");
Map<Locale, ResourceBundle> resources = getFieldValue(appBundle, "resources");
resources.clear();
}
@SuppressWarnings("unchecked")
private static <T> T getFieldValue(Object object, String fieldName) {
try {
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return (T) field.get(object);
} catch (Exception e) {
return null;
}
}
(замените вспомогательный метод getFieldValue с помощью собственного любимого рефлексивного использования, если это необходимо, и по возможности посыпать исключениями и нулевыми обработчиками)
Вы даже можете избежать импорта классов сварки и jsf-impl в свой модуль с еще несколькими линиями отражения:
Class<?> applicationAssociateClass = Class.forName("com.sun.faces.application.ApplicationAssociate");
Method getCurrentInstance = applicationAssociateClass.getMethod("getCurrentInstance");
Object applicationAssociate = getCurrentInstance.invoke(null);
Method getResourceBundles = applicationAssociate.getClass().getMethod("getResourceBundles");
Map<String, ?> resourceBundles = (Map<String, ?>)getResourceBundles.invoke(applicationAssociate);
Object appBundle = resourceBundles.get(name);
Map<Locale, ResourceBundle> resources = getFieldValue(appBundle, "resources");
resources.clear();
(хорошо работает с Wildfly 10)