Spring IoC контейнер: дополнительные возможности ApplicationContext, интернационализация с использованием MessageSource

Интерфейс ApplicationContext расширяет интерфейс под названием MessageSource и, следовательно, обеспечивает функциональность интернационализации (“i18n”). Spring также предоставляет интерфейс HierarchicalMessageSource, который может разрешать сообщения иерархически. Вместе эти интерфейсы обеспечивают основу, на которой Spring влияет на разрешение сообщений. Методы, определенные в этих интерфейсах, включают:

  • String getMessage(String code, Object[] args, String default, Locale loc): основной метод, используемый для получения сообщения из MessageSource. Если сообщение для указанной локали не найдено, используется сообщение по умолчанию. Любые переданные аргументы становятся значениями замены с использованием функции MessageFormat, предоставляемой стандартной библиотекой.
  • String getMessage(String code, Object[] args, Locale loc): по сути то же самое, что и предыдущий метод, но с одним отличием: нельзя указать сообщение по умолчанию. Если сообщение не может быть найдено, создается исключение NoSuchMessageException.
  • String getMessage(MessageSourceResolvable resolvable, Locale locale): все свойства, используемые в предыдущих методах, также заключены в класс с именем MessageSourceResolvable, который можно использовать с этим методом.

Когда ApplicationContext загружается, он автоматически ищет bean-компонент MessageSource, определенный в контексте. Компонент должен иметь имя messageSource. Если такой bean-компонент найден, все вызовы предыдущих методов делегируются источнику сообщения (message source). Если источник сообщения не найден, ApplicationContext пытается найти родителя, содержащего bean-компонент с тем же именем. Если это так, он использует этот компонент как MessageSource. Если ApplicationContext не может найти какой-либо источник для сообщений, создается пустой DelegatingMessageSource, чтобы иметь возможность принимать вызовы методов, определенных выше.

Spring предоставляет две реализации MessageSource: ResourceBundleMessageSource и StaticMessageSource. Оба реализуют HierarchicalMessageSource, чтобы выполнять вложенные сообщения. StaticMessageSource используется редко, но предоставляет программные способы добавления сообщений в источник. В следующем примере показан ResourceBundleMessageSource:

<beans>
    <bean id="messageSource"
            class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basenames">
            <list>
                <value>format</value>
                <value>exceptions</value>
                <value>windows</value>
            </list>
        </property>
    </bean>
</beans>

В примере предполагается, что у вас есть три пакета ресурсов, называемые format, exceptions и windows, определенными в вашем пути к классам. Любой запрос на разрешение сообщения обрабатывается стандартным для JDK способом разрешения сообщений через объекты ResourceBundle. Для целей примера предположим, что содержимое двух из вышеуказанных файлов пакета ресурсов выглядит следующим образом:

# в format.properties
message=Alligators rock!

# в exceptions.properties
argument.required=The {0} argument is required.

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

Java

public static void main(String[] args) {
    MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
    String message = resources.getMessage("message", null, "Default", Locale.ENGLISH);
    System.out.println(message);
}

Kotlin

fun main() {
    val resources = ClassPathXmlApplicationContext("beans.xml")
    val message = resources.getMessage("message", null, "Default", Locale.ENGLISH)
    println(message)
}

Итоговый результат вышеуказанной программы выглядит следующим образом:

Alligators rock!

Подводя итог, MessageSource определен в файле beans.xml, который существует в корне вашего пути к классам. Определение bean-компонента messageSource ссылается на ряд пакетов ресурсов через его свойство basenames. Три файла, которые передаются в списке свойству basenames, существуют как файлы в корне вашего пути к классам и называются format.properties, exceptions.properties и windows.properties соответственно.

В следующем примере показаны аргументы, переданные при поиске сообщения. Эти аргументы преобразуются в объекты String и вставляются в заполнители в поисковом сообщении.

<beans>

    <!-- этот MessageSource используется в веб-приложении -->
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename" value="exceptions"/>
    </bean>

    <!-- позволяет внедрить указанный выше MessageSource в этот POJO -->
    <bean id="example" class="com.something.Example">
        <property name="messages" ref="messageSource"/>
    </bean>

</beans>

Java

public class Example {

    private MessageSource messages;

    public void setMessages(MessageSource messages) {
        this.messages = messages;
    }

    public void execute() {
        String message = this.messages.getMessage("argument.required",
            new Object [] {"userDao"}, "Required", Locale.ENGLISH);
        System.out.println(message);
    }
}

Kotlin

class Example {

    lateinit var messages: MessageSource

    fun execute() {
        val message = messages.getMessage("argument.required",
                arrayOf("userDao"), "Required", Locale.ENGLISH)
        println(message)
    }
}

Результат вызова метода execute() будет следующим:

The userDao argument is required.

Что касается интернационализации (“i18n”), различные реализации MessageSource Spring следуют тем же правилам разрешения локали и отступления, что и стандартный JDK ResourceBundle. Короче говоря, продолжая пример messageSource, определенный ранее, если вы хотите разрешить сообщения в соответствии с британской (en-GB) локалью, вы должны создать файлы с именами format_en_GB.properties, exceptions_en_GB.properties и windows_en_GB.properties соответственно.

Обычно разрешение локали управляется окружающей средой приложения. В следующем примере локаль, по которой разрешаются (британские) сообщения, указывается вручную:

# в exceptions_en_GB.properties
argument.required=Ebagum lad, the ''{0}'' argument is required, I say, required.

Java

public static void main(final String[] args) {
    MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
    String message = resources.getMessage("argument.required",
        new Object [] {"userDao"}, "Required", Locale.UK);
    System.out.println(message);
}

Kotlin

fun main() {
    val resources = ClassPathXmlApplicationContext("beans.xml")
    val message = resources.getMessage("argument.required",
            arrayOf("userDao"), "Required", Locale.UK)
    println(message)
}

Результат выполнения вышеуказанной программы выглядит следующим образом:

Ebagum lad, the 'userDao' argument is required, I say, required.

Вы также можете использовать интерфейс MessageSourceAware для получения ссылки на любой объект MessageSource, который был определен. Любой bean-компонент, определенный в ApplicationContext, который реализует интерфейс MessageSourceAware, вводится с MessageSource контекста приложения при создании и настройке bean-компонента.

В качестве альтернативы ResourceBundleMessageSource Spring предоставляет класс ReloadableResourceBundleMessageSource. Этот вариант поддерживает тот же формат файла пакета, но является более гибким, чем стандартная реализация ResourceBundleMessageSource на основе JDK. В частности, он позволяет читать файлы из любого местоположения ресурсов Spring (не только из пути к классам) и поддерживает горячую перезагрузку файлов свойств пакета (при их эффективном кэшировании между ними).


Читайте также:


Комментарии

Популярные сообщения из этого блога

Методы класса Object в Java

Как получить текущий timestamp в Java

Основные опции JVM для повышения производительности и отладки