Lesen des Spring-Quellcodes 15: MessageSource initialisieren

Dies ist der 30. Tag meiner Teilnahme an der „Nuggets Daily New Plan·August Update Challenge“, klicken Sie hier, um die Details der Veranstaltung anzuzeigen

Basierend auf Spring Framework v5.2.6.RELEASE

Fortsetzung des vorherigen Artikels: Spring Source Code Reading 14: BeanPostProcessor registrieren

Rekapitulieren

Im vorherigen Artikel, ApplicationContext initialisiert den Spring-Container , wird erwähnt, dass die AbstractApplicationContext#refreshMethode eine sehr wichtige Methode ist, die den gesamten Prozess der Spring-Container-Initialisierung umfasst. Eine Reihe neuerer Artikel stellt eine eingehende Analyse der spezifischen Prinzipien jedes Schritts in dieser Methode dar. Dieser Artikel analysiert dann die Initialisierung von MessageSource, das ist refreshdiese Codezeile in der Methode:

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

Lassen Sie uns zunächst vorstellen, was eine MessageSource ist.

Was ist MessageSource

Im Spring wird MessageSource hauptsächlich verwendet, um das Problem der Internationalisierung zu behandeln, von dem oft gesprochen wird i18n(Internationalization).

Wenn beispielsweise die von uns entwickelte Website an die Sprachen mehrerer Länder und Regionen angepasst werden muss, müssen wir verschiedene Sprachen verwenden, um den Inhalt der Website anzuzeigen.Dies erfordert die Verwendung i18nvon Komponenten. MessageSource ist eine i18nKomponente in Frühling.

MessageSource selbst ist eine Schnittstelle, die Schnittstelle ist wie folgt definiert:

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;

}
复制代码

Alle drei Methoden werden verwendet, codeum den lokalisierten Text einer bestimmten Nachricht durch einen angegebenen Bezeichner ( ) und Sprachinformationen zu erhalten. Wichtige Implementierungsklassen in Bezug auf MessageSource und die Beziehung zwischen ihnen sind wie folgt:

Es gibt eine wichtige Unterschnittstelle HierarchicalMessageSource, die die Funktion der hierarchischen Verarbeitung von Nachrichten bereitstellt. Es folgt die Definition der Schnittstelle.

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语句块的逻辑。下面分别来说分析。

Wenn beanFactoryes eine benannte messageSourceBean gibt, rufen Sie eine Instanz dieser Bean ab und legen Sie sie als MessageSource des aktuellen Kontexts fest. Auch hier gibt es eine Wertung: Wenn die erhaltene messageSourcedie HierarchicalMessageSource-Schnittstelle implementiert und das aktuelle Kontextattribut parentnicht leer ist, wird sie als übergeordnete Nachrichtenquelle parentzugewiesen .messageSourcemessageSource

Wenn wir in der Konfigurationsdatei keine MessageSource konfigurieren, erstellt Spring eine, weist sie einer messageSourceMitgliedsvariablen des aktuellen Kontexts zu und registriert beanFactorysie.

Der hier erstellte Nachrichtenquellentyp ist DelegatingMessageSource. Die Logik von DelegatingMessageSource besteht darin, die Nachricht direkt von der übergeordneten Nachrichtenquelle abzurufen oder eine Standardnachricht gemäß dem bereitgestellten Inhalt zu generieren, andernfalls wird null zurückgegeben oder eine Ausnahme ausgelöst. Ihre Rolle besteht darin, dass beim Aufrufen der Methode in der MessageSource des aktuellen Kontexts eine Implementierungsklasse vorhanden ist, die auf den Methodenaufruf antwortet, und das war's.

nachverfolgen

Dieser Teil des in diesem Artikel vorgestellten Inhalts ist relativ einfach, und die Verwendung von MessageSource in der tatsächlichen Entwicklung ist nicht hoch. Der Code für die Initialisierung des Spring-Containers wird später analysiert.

Ich denke du magst

Origin juejin.im/post/7135649446930415653
Empfohlen
Rangfolge