当前位置: 首页 > 知识库问答 >
问题:

自定义 Spring 启动器:您如何向 MessageSource 贡献 i18n 消息?

阚砚文
2023-03-14

我正在编写一个自定义的 Spring 启动启动器,其他开发人员将放入他们的应用程序中,这个启动器包含开箱即用的控制器和 UI 屏幕。

这些UI屏幕是国际化的,i18n键/值在一个包文件中:< code > com/foo/where/i18n . properties 。

我想确保当我的starter在启动时加载时,这些i18n.properties在应用程序的< code>MessageSource中自动可用,这样我的UI页面就可以工作(通过普通的Spring Controller ViewResolver视图实现呈现)而无需应用程序开发人员自己指定这个文件。

换句话说,他们应该能够将我的启动器添加到他们的运行时类路径中,并且一切都“正常工作”,而无需配置任何内容。

现在,我发现应用程序html" target="_blank">开发人员可以创建自己的< code > src/main/resources/messages . properties 文件,并在< code > application . properties 中手动配置附加消息文件:

spring.messages.basename = messages, com.foo.wherever.i18n

这将起作用。

但是,这需要满足以下两项条件:

  1. 他们必须手动配置<code>spring.messages。basename</code>属性-它不是自动的。和
  2. 他们必须有自己的<code>消息。properties</code>文件的应用程序类路径中。如果<code>消息。properties</code>文件不存在,<code>spring.messages。basename</code>甚至不起作用。即使他们不关心i18n,这仍然是必需的——并不可取

我想我可以移动我的i18n。属性文件转换为类路径:/messages。jar中的properties文件,但这似乎不是一个好的解决方案:如果应用程序开发人员有自己的消息。属性文件只读取其中一个属性,从而丢失消息值。

看起来Spring Boot MessageSourceAutoCon人和应该有一个CompositeMessageSource的概念,它迭代一个或多个MessageSource实例,这些实例在Spring Application ationContext中可用(和ed),并由DispatcherServlet使用。这将允许任何启动器通过在其自动配置中声明MessageSource来贡献可用消息

有可能做到我要求的吗?对应用程序开发人员来说,最“不干涉”的解决方案是什么?

共有3个答案

锺功
2023-03-14

我意识到这是一个老掉牙的问题,但前几天我遇到了同样的问题,并写了一篇关于我决定如何解决这个问题的博文。我想我应该在这里分享它,因为我从这个线程中得到了一些解决方案的灵感。

简而言之,它采用了 sodik 拦截 MessageSource bean 创建的想法,但我使用的是 BeanPostProcessor,而不是使用 BeanFactoryPostProcessor,而不是替换应用程序上下文中的原始 MessageSource,我只是添加我自己的作为其父级:

@Bean
BeanPostProcessor messageSourceCustomExtender() {
    return new BeanPostProcessor() {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }

        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof HierarchicalMessageSource && beanName.equals("messageSource")) {
                ResourceBundleMessageSource parent = new ResourceBundleMessageSource();
                parent.setBasename("custom");

                ((HierarchicalMessageSource) bean).setParentMessageSource(parent);
            }

            return bean;
        }
    };
}

你可以阅读完整的博客文章,其中我解释了一些关于我的解决方案的警告:http://www.thomaskasene.com/2016/08/20/custom-spring-boot-starter-messagesource/

经过一些修补,我意识到使用< code > BeanFactoryPostProcessor 是错误的,因为它将导致过早地创建原始的< code>MessageSource bean,并忽略应用程序属性(最重要的是< code > spring . messages . basename )。这意味着应用程序将无法配置这些属性。请参见下面的BeanFactoryPostProcessor文档摘录。

BeanFactoryPostProcessor可以与bean定义交互并修改bean定义,但不能修改bean实例。这样做可能会导致过早的bean实例化,违反容器并导致意想不到的副作用。如果需要bean实例交互,请考虑实现BeanPostProcessor。

我已经更新了上面的示例以改用 BeanPostProcessor,这会更改 Bean 实例而不是 Bean 定义。

师野
2023-03-14

也许这是一个长远的目标,但你可以尝试使用BeanFactoryPostProcessor。

想法如下:

> < li>

将“message source”bean从应用程序上下文中取出。请注意,如果开发人员想要使用自己的实现,并且不使用spring boot自动配置,那么它可能是但不是必须是spring boot的。

将其替换为您自己的实现,该实现尝试解析“您的键”,其余委托给原始消息源。如果您想让开发人员覆盖您的翻译,反之亦然(如果原始消息源不为未知键抛出异常,可能会出现问题)。

但是也许有更好的方法。

祝昊东
2023-03-14

我按以下方式设置了它。我目前只支持en_US但它被设置为使用国际化(i18n)处理任意数量的语言。

在此处查看代码要点:github要点上的代码

将这些beans添加到您的Application.java中,以设置您的默认语言环境并配置您的消息属性的位置

服务将从会话中获取默认区域设置,然后从您的 prop 获取消息文本

注入消息svc,然后传递id以从props文件中获取值

转到/资源:

  • 创建区域设置文件
  • 创建一个名为 messages_en_US.properties 的文件

您可以在此处查看有关此主题的更完整的文章:Spring Boot国际化使用消息属性

在此处查看代码要点:github要点上的代码

 类似资料:
  • 问题内容: 我正在编写一个自定义的Spring Boot入门程序,其他开发人员将其放入他们的应用程序中,并且该入门程序包含开箱即用的控制器和UI屏幕。 这些UI屏幕已经国际化,并且i18n键/值在打包文件中:。 我想确保在启动时加载启动程序时,这些i18n.properties可以自动在应用程序中使用,以便我的UI页面可以工作(通过常规Spring Controller + ViewResolve

  • 文档更新 如果修改了组件代码,需要在组件目录的metas.yml加上changes,直接使用next作为版本号(如果已经存在该版本号,则直接添加变更条目即可)。 中括号内为变更类型,可选值 fix enhance feature change 比如: changes: next: en: - '[fix] fix *** bug #issueId' - '[fe

  • 在 Github 上 Fork 项目到自己的仓库。 将 fork 后的项目拉到本地: git clone https://github.com/<user-name>/kubernetes-handbook。 新建一个分支,并添加或编辑内容:git checkout -b new-branch。 提交并推送到 github:git commit -am "comments"; git push。

  • 我们非常欢迎您的贡献和加入,无论是微不足道的清理或大的新功能。我们希望为每个编程语言提供高质量、有良好文档的代码。 这也不是代码是唯一有贡献项目的方式。我们非常重视文档、与其他项目的集成,并欣然接受这些方面的改进。 联系我们 Nacos Gitter-https://gitter.im/alibaba/nacos Nacos 微博-https://weibo.com/u/6574374908 Na

  • 在Github上Fork到自己的仓库 将fork后的项目拉到本地: git clone https://github.com/<user-name>/sdn-handbook 新建一个分支,并添加或编辑内容:git checkout -b new-branch 提交并推送到github:git commit -am "comments"; git push 在Github上提交Pull Reque

  • 我正在开发一个Spring启动自定义启动器,其中pom包含一些依赖项(其他启动器、库),并且这个启动器执行一些关于jwt过滤的配置,以允许过滤器处于安全水位。问题是当我在另一个项目(starter-消费者)中添加我的自定义启动器作为pom依赖项时,它似乎检测到我要导入的类,但IntelliJ什么也没做。 也许我没有正确打包启动器,或者至少我在里面编码的类。启动器在pom中包含的其他依赖项被成功添加