@
目錄
MessageSourceAutoConfiguration是國際化語言i18n的自動配置類
MessageSourceAutoConfiguration.ResourceBundleCondition 源碼:
protected static class ResourceBundleCondition extends SpringBootCondition {
//定義一個map緩存池
private static ConcurrentReferenceHashMap<String, ConditionOutcome> cache = new ConcurrentReferenceHashMap<>();
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
String basename = context.getEnvironment().getProperty("spring.messages.basename", "messages");
ConditionOutcome outcome = cache.get(basename);//緩存拿得到,直接從緩存池讀取
if (outcome == null) {//緩存拿不到,重新讀取
outcome = getMatchOutcomeForBasename(context, basename);
cache.put(basename, outcome);
}
return outcome;
}
private ConditionOutcome getMatchOutcomeForBasename(ConditionContext context, String basename) {
ConditionMessage.Builder message = ConditionMessage.forCondition("ResourceBundle");
for (String name : StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(basename))) {
for (Resource resource : getResources(context.getClassLoader(), name)) {
if (resource.exists()) {
//匹配resource bundle資源
return ConditionOutcome.match(message.found("bundle").items(resource));
}
}
}
return ConditionOutcome.noMatch(message.didNotFind("bundle with basename " + basename).atAll());
}
//解析資源文件
private Resource[] getResources(ClassLoader classLoader, String name) {
String target = name.replace('.', '/');//spring.messages.basename參數值的點號換成斜桿
try {
return new PathMatchingResourcePatternResolver(classLoader)
.getResources("classpath*:" + target + ".properties");
}
catch (Exception ex) {
return NO_RESOURCES;
}
}
}
ok,這個自動配置類還是比較容易理解的,所以本博客列舉一些注意要點
1、spring.messages.cache-duration
- spring.messages.cache-duration在2.2.1版本,指定的是s為單位,找到SpringBoot的MessageSourceAutoConfiguration自動配置類
2、LocaleResolver 的方法名必須為localeResolver
- 如下代碼,LocaleResolver 的方法名必須為localeResolver,否則會報錯
@Bean
public LocaleResolver localeResolver(){
CustomLocalResolver localResolver = new CustomLocalResolver();
localResolver.setDefaultLocale(webMvcProperties.getLocale());
return localResolver;
}
原理:
跟一下源碼,點進LocaleChangeInterceptor類
DispatcherServlet是Spring一個很重要的分發器類,在DispatcherServlet的一個init方法里找到這個LocaleResolver的init方法
這個IOC獲取的bean類名固定為localeResolver,寫例子的時候,我就因為改了bean類名,導致一直報錯,跟了源碼才知道Bean類名要固定為localeResolver
3、默認LocaleResolver
繼續跟源碼,拋異常的時候,也是會獲取默認的LocaleResolver的
找到一個properties配置文件,全局搜索
找到資源文件,確認,還是默認為AcceptHeaderLocaleResolver
4、指定默認的locale
- WebMvcAutoConfiguration的自動配置
配置了locale屬性的時候,還是選用AcceptHeaderLocaleResolver作為默認的LocaleResolver
spring.mvc.locale=zh_CN
WebMvcAutoConfiguration.localeResolver方法源碼,ConditionalOnMissingBean主鍵的意思是LocaleResolver沒有自定義的時候,才作用,ConditionalOnProperty的意思,有配了屬性才走這里的邏輯
5、localeChangeInterceptor指定傳參
- 攔截器攔截的請求參數默認為locale,要使用其它參數,必須通過攔截器設置 ,eg:
localeChangeInterceptor.setParamName("lang");
附錄:
- Locale解析器種類
LocalResolver種類有:CookieLocaleResolver(Cookie)、SessionLocaleResolver(會話)、FixedLocaleResolver、AcceptHeaderLocaleResolver(默認)、.etc
具體實現,參考我的博客:SpringBoot系列之i18n國際化多語言支持教程