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#refresh
mé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 refresh
esta 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 i18n
de componentes. MessageSource es un i18n
componente 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 code
obtener 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 beanFactory
hay un messageSource
bean 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 messageSource
implementa la interfaz HierarchicalMessageSource y el atributo de contexto actual parent
no está vacío, se parent
asignará messageSource
como la messageSource
fuente del mensaje principal.
Si no configuramos un MessageSource en el archivo de configuración, Spring creará uno, lo asignará a una messageSource
variable miembro del contexto actual y beanFactory
lo 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.