Spring 多模块配置国际化,MessageSource只能加载一个文件
前言
在写项目配置国际化的时候,因为我有多个模块项目:common、admin、image等,各自模块都有i18n的文件。
但在配置MessageSource的时候发现只能加载一个文件,其他文件被丢弃了,导致code会找不到。
后面在stackoverflow中找到了相关文章对其进行解释了:
https://stackoverflow.com/questions/3888832/does-spring-messagesource-support-multiple-class-path
1、原版写法(错误):
@Bean
public MessageSource messageSource() {ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();messageSource.setBasenames("classpath*:i18n/messages");messageSource.setDefaultEncoding("UTF-8");messageSource.setUseCodeAsDefaultMessage(true);return messageSource;
}
原因解释:
classpath*
语法是 Spring 的一种机制,它允许代码为给定路径加载多个资源。非常方便。然而, ResourceBundleMessageSource
使用标准的 java.util.ResourceBundle
来加载资源,这是一种更简单、更简单的机制,它将加载给定路径的第一个资源,并忽略其他所有内容。
2、解决方法
自定义一个类SmReloadableResourceBundleMessageSource,继承ResourceBundleMessageSource
类,去重写 refreshProperties 方法,该方法支持两种类型的 basenames(classpath*: 和 /WEB-INF/)。
public class SmReloadableResourceBundleMessageSource extends ReloadableResourceBundleMessageSource {private static final String PROPERTIES_SUFFIX = ".properties";private PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();@Overrideprotected PropertiesHolder refreshProperties(String filename, PropertiesHolder propHolder) {if (filename.startsWith(PathMatchingResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX)) {return refreshClassPathProperties(filename, propHolder);} else {return super.refreshProperties(filename, propHolder);}}private PropertiesHolder refreshClassPathProperties(String filename, PropertiesHolder propHolder) {Properties properties = new Properties();long lastModified = -1;try {Resource[] resources = resolver.getResources(filename + PROPERTIES_SUFFIX);for (Resource resource : resources) {String sourcePath = resource.getURI().toString().replace(PROPERTIES_SUFFIX, "");PropertiesHolder holder = super.refreshProperties(sourcePath, propHolder);properties.putAll(holder.getProperties());if (lastModified < resource.lastModified())lastModified = resource.lastModified();}} catch (IOException ignored) {}return new PropertiesHolder(properties, lastModified);}
}
之后再去替换ReloadableResourceBundleMessageSource 类。
@Beanpublic MessageSource messageSource() {SmReloadableResourceBundleMessageSource messageSource = new SmReloadableResourceBundleMessageSource();messageSource.setBasenames("classpath*:/i18n/messages");messageSource.setDefaultEncoding("UTF-8");messageSource.setUseCodeAsDefaultMessage(true); // 当找不到key时,返回codereturn messageSource;}