「ナゲッツデイリー新プラン・8月アップデートチャレンジ」参加30日目、イベント詳細はこちら
Spring Framework v5.2.6.RELEASE に基づく
要約
前回の記事でApplicationContext が Spring コンテナを初期化すると述べましたが、このAbstractApplicationContext#refresh
メソッドは非常に重要なメソッドであり、Spring コンテナの初期化の全プロセスが含まれます。最近の一連の記事では、このメソッドの各ステップの具体的な原則を詳細に分析しています。次に、MessageSource の初期化を分析しています。これはrefresh
、メソッド内の次のコード行です。
// Initialize message source for this context.
initMessageSource();
复制代码
最初に MessageSource とは何かを紹介しましょう。
メッセージソースとは
i18n
Spring では、MessageSource は主に、よく言われる国際化 (Internationalization)の問題に対処するために使用されます。
例えば、開発するウェブサイトが複数の国や地域の言語に対応する必要がある場合、ウェブサイトのコンテンツを表示するために異なる言語を使用する必要があり、これにi18n
はコンポーネントをi18n
使用する必要があります。春。
MessageSource 自体はインターフェースであり、インターフェースは次のように定義されます。
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;
}
复制代码
3 つのメソッドはすべてcode
、指定された識別子 ( ) と言語情報によって特定のメッセージのローカライズされたテキストを取得するために使用されます。MessageSource に関連する重要な実装クラスとそれらの間の関係は次のとおりです。
メッセージの階層処理機能を提供する、重要な HierarchicalMessageSource サブインターフェースがあります。以下は、インターフェイスの定義です。
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
语句块的逻辑。下面分别来说分析。
beanFactory
名前付きBean がある場合messageSource
は、この Bean のインスタンスを取得し、現在のコンテキストの MessageSource として設定します。ここにも判断があり、取得したものmessageSource
が HierarchicalMessageSource インターフェースを実装しており、現在のコンテキストparent
属性が空でない場合、親メッセージソースとしてparent
割り当てられます。messageSource
messageSource
構成ファイルで MessageSource を構成しない場合、Spring はそれを作成しmessageSource
、現在のコンテキストのメンバー変数に割り当てて登録beanFactory
します。
ここで作成されるメッセージ ソース タイプは DelegatingMessageSource です. DelegatingMessageSource のロジックは、親メッセージ ソースからメッセージを直接取得するか、提供されたコンテンツに従って既定のメッセージを生成することです。それ以外の場合は、null を返すか、例外をスローします。その役割は、現在のコンテキストの MessageSource 内のメソッドが呼び出されたときに、メソッド呼び出しに応答する実装クラスが存在することです。それだけです。
ファローアップ
この記事で紹介した内容のこの部分は比較的単純であり、実際の開発での MessageSource の使用率は高くありません。Spring コンテナーの初期化のコードは後で分析します。