前言

由于自己一直在做 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 来确保该内容只会被加载一次。

需要思考的问题

  1. 要考虑是否会被重复加载的问题 (@ConditionalOnMissingBean)
  2. messageSource.getMessage() 触发报错,是否应该返回原内容
  3. 适当的使用 log 进行打印日志
最后修改:2023 年 01 月 10 日
如果觉得我的文章对你有用,请随意赞赏