Lectura de código fuente de Spring 15: Inicializar MessageSource

Este es el día 30 de mi participación en el "Nuggets Daily New Plan·August Update Challenge", haz clic para ver los detalles del evento

Basado en Spring Framework v5.2.6.RELEASE

Continuación del artículo anterior: Código fuente de Spring, lectura 14: Registro de BeanPostProcessor

Resumen

En el artículo anterior , ApplicationContext inicializa el contenedor Spring , se menciona que el AbstractApplicationContext#refreshmétodo es un método muy importante, que incluye todo el proceso de inicialización del contenedor Spring. Una serie de artículos recientes son un análisis en profundidad de los principios específicos de cada paso en este método. Este artículo luego analiza la inicialización de MessageSource, que es refreshesta línea de código en el método:

// Initialize message source for this context.
initMessageSource();
复制代码

Primero, presentemos qué es un MessageSource.

¿Qué es MessageSource?

En Spring, MessageSource se utiliza principalmente para tratar el problema de la internacionalización, que a menudo se dice i18n(internacionalización).

Por ejemplo, si el sitio web que desarrollamos necesita adaptarse a los idiomas de varios países y regiones, necesitamos usar diferentes idiomas para mostrar el contenido del sitio web. Esto requiere el uso i18nde componentes. MessageSource es un i18ncomponente en Primavera.

MessageSource en sí mismo es una interfaz, la interfaz se define de la siguiente manera:

public interface MessageSource {
@Nullable
   String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);
String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;

}
复制代码

Los tres métodos se utilizan para codeobtener el texto localizado de un mensaje específico mediante un identificador específico ( ) e información de idioma. Las clases de implementación importantes relacionadas con MessageSource y la relación entre ellas son las siguientes:

Hay una subinterfaz HierarchicalMessageSource importante, que proporciona la función de procesamiento jerárquico de mensajes. A continuación se muestra la definición de la interfaz.

public interface HierarchicalMessageSource extends MessageSource {
void setParentMessageSource(@Nullable MessageSource parent);
@Nullable
   MessageSource getParentMessageSource();
}
复制代码

简而言之,就是给 MessageSource 提供了父子关系,开发者可以用一个父级的 MessageSource 处理公共的消息内容,子级的 MessageSource 只需要处理对应模块的消息内容即可。当通过子级的 MessageSource 获取不到消息内容是,就会到父级的 MessageSource 中获取。

接下来是两个比较典型的实现类,ResourceBundleMessageSource 和 StaticMessageSource。StaticMessageSource 是一个静态的消息源,需要提前硬编码内容,因此不是很常用。比较常用的是 ResourceBundleMessageSource,它从给定路径的消息文件中加载内容,供程序获取。

初始化 MessageSource

接下来看 Spring 初始化 MessageSource 的过程,也就是 initMessageSource 的代码。

protected void initMessageSource() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
      this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
      // Make MessageSource aware of parent MessageSource.
      if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
         HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
         if (hms.getParentMessageSource() == null) {
            // Only set parent context as parent MessageSource if no parent MessageSource
            // registered already.
            hms.setParentMessageSource(getInternalParentMessageSource());
         }
      }
      if (logger.isTraceEnabled()) {
         logger.trace("Using MessageSource [" + this.messageSource + "]");
      }
   }
   else {
      // Use empty MessageSource to be able to accept getMessage calls.
      DelegatingMessageSource dms = new DelegatingMessageSource();
      dms.setParentMessageSource(getInternalParentMessageSource());
      this.messageSource = dms;
      beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
      if (logger.isTraceEnabled()) {
         logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
      }
   }
}
复制代码

首先,获取到当前上下文内部的 BeanFactory,之后整个方法体都是一个if-else语句块,判断条件是 BeanFactory 中是否包含名为MESSAGE_SOURCE_BEAN_NAME的 Bean。

public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource";
复制代码

也就是 Spring 在容器中查找 MessageSource 时使用的是固定的名称messageSource,因此,如果要在配置文件中配置 MessageSource,需要把bean标签的id属性设置为messageSource,才能被 Spring 作为消息源。如果我们在配置文件中配置了messageSource,则会执行if语句块的逻辑,否则执行else语句块的逻辑。下面分别来说分析。

Si beanFactoryhay un messageSourcebean con nombre, obtenga una instancia de este bean y configúrelo como MessageSource del contexto actual. También hay un juicio aquí, si el obtenido messageSourceimplementa la interfaz HierarchicalMessageSource y el atributo de contexto actual parentno está vacío, se parentasignará messageSourcecomo la messageSourcefuente del mensaje principal.

Si no configuramos un MessageSource en el archivo de configuración, Spring creará uno, lo asignará a una messageSourcevariable miembro del contexto actual y beanFactorylo registrará.

El tipo de origen del mensaje creado aquí es DelegatingMessageSource. La lógica de DelegatingMessageSource es obtener directamente el mensaje del origen del mensaje principal o generar un mensaje predeterminado de acuerdo con el contenido proporcionado; de lo contrario, devolverá un valor nulo o generará una excepción. Su función es que cuando se llama al método en el MessageSource del contexto actual, hay una clase de implementación para responder a la llamada del método, y eso es todo.

hacer un seguimiento

Esta parte del contenido presentado en este artículo es relativamente simple y el uso de MessageSource en el desarrollo real no es alto. El código para la inicialización del contenedor Spring se analizará más adelante.

Supongo que te gusta

Origin juejin.im/post/7135649446930415653
Recomendado
Clasificación