前言
由于自己一直在做 i18n 国际化改造,因此替换文件或者重复复制粘贴 Util 工具类是不现实的,所以我搞了一个 Maven 依赖,通过使用此包来 getMessage
步骤
首先要创建一个Spring项目,结构如下
在 AutoConfiguration
中需要注入我们想要的 Service Bean。例如图中的 InternationalService
。代码如下:
package com.domcer.internationalspringbootstarter.config;
import com.domcer.internationalspringbootstarter.service.InternationalService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
/**
* @Author hang.wang
* @Date 2022/12/6 10:27
*/
@Slf4j
@Configuration
@ConditionalOnClass(InternationalService.class)
public class AutoConfiguration {
@Resource
private MessageSource messageSource;
@Bean
@ConditionalOnMissingBean(InternationalService.class)
public InternationalService internationalService(){
log.info("message source init success!");
return new InternationalService(messageSource);
}
}
使用@ConditionalOnClass
和@ConditionalOnMissingBean
是为了防止重复注入
导致的冲突问题,因为在项目中可能会有多个模块进行引用,但是他们已经被Spring统一管理了,无需再次初始化
同时,需要在 resource
目录下创建 META-INF
文件夹,并创建 spring.factories
文件,文件中需要写入以下内容
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.domcer.internationalspringbootstarter.config.AutoConfiguration
第二行的路径代表的是需要自动加载哪一个类
InternationalService 代码
package com.domcer.internationalspringbootstarter.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.context.i18n.LocaleContextHolder;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @Author hang.wang
* @Date 2022/12/6 10:29
*/
@Slf4j
public class InternationalService {
private MessageSource messageSource;
private static final AtomicBoolean initFlag = new AtomicBoolean(false);
public InternationalService(MessageSource messageSource) {
if (initFlag.compareAndSet(false, true)) {
this.messageSource = messageSource;
log.info("message source init successful!");
}
}
public String getMessage(String path) {
if (!initFlag.get()) {
throw new IllegalStateException("message source not init!");
}
try {
return messageSource.getMessage(path, null, LocaleContextHolder.getLocale());
} catch (NoSuchMessageException e) {
log.error("message key not found: {}", path, e);
return path;
}
}
}
当一个项目使用此starter时,必须确保的是该项目是springboot工程,否则该starter并不会被启用。
此内容写的是关于国际化改造的代码,在 getMessage
方法中进行了 try...catch
,当没有找到相应的 key
时,将会返还原本的内容。
在此包被加载时,通过 AutoConfiguration
来调用 InternationalService
的构造方法,并且传递了 messageSource
对象。
使用 AtomicBoolean
来确保该内容只会被加载一次。
需要思考的问题
- 要考虑是否会被重复加载的问题
(@ConditionalOnMissingBean)
- 当
messageSource.getMessage()
触发报错,是否应该返回原内容 - 适当的使用
log
进行打印日志