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#refresh
Methode 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 refresh
diese 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 i18n
von Komponenten. MessageSource ist eine i18n
Komponente 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, code
um 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 beanFactory
es eine benannte messageSource
Bean 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 messageSource
die HierarchicalMessageSource-Schnittstelle implementiert und das aktuelle Kontextattribut parent
nicht leer ist, wird sie als übergeordnete Nachrichtenquelle parent
zugewiesen .messageSource
messageSource
Wenn wir in der Konfigurationsdatei keine MessageSource konfigurieren, erstellt Spring eine, weist sie einer messageSource
Mitgliedsvariablen des aktuellen Kontexts zu und registriert beanFactory
sie.
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.