Spring MessageSource是否支持多类路径?

2022-09-02 05:31:58

我正在使用Spring框架为我们基于Web的应用程序设计一个插件系统。插件是类路径上的 jar。所以我能够获得诸如jsp之类的来源,请参阅下文

ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] pages = resolver.getResources("classpath*:jsp/*jsp");

目前为止,一切都好。但是我对消息源有问题。在我看来,ReloadableResourceBundleMessageSource#setBasename不支持通过“classpath*:”的多个类路径,如果我只使用“classpath:”,我只从一个插件获得messageSource。

有没有人知道如何从所有插件注册messageSources?是否存在这样的 MessageSource 实现?


答案 1

使用@seralex-vi基名/WEB-INF/messages的解决方案不起作用。

我覆盖了 ReloadableResourceBundleMessageSource 类上的方法 refreshProperties,它执行两种类型的基名(classpath*: 和 /WEB-INF/)

public class SmReloadableResourceBundleMessageSource extends ReloadableResourceBundleMessageSource {

private static final String PROPERTIES_SUFFIX = ".properties";

private PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();

@Override
protected 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);
}

在 spring 上下文上.xml您必须具有类路径 *: 前缀

<bean id="messageSource" class="SmReloadableResourceBundleMessageSource">
    <property name="basenames">
        <list>
            <value>/WEB-INF/i18n/enums</value>
            <value>/WEB-INF/i18n/messages</value>
            <value>classpath*:/META-INF/messages-common</value>
            <value>classpath*:/META-INF/enums</value>
        </list>
    </property>
</bean>

答案 2

这里的问题不在于多个类路径或类装入器,而在于代码将尝试为给定路径加载多少资源。

语法是Spring机制,它允许代码为给定路径加载多个资源。非常方便。但是,使用标准来加载资源,这是一种更简单,更愚蠢的机制,它将加载给定路径的第一个资源,并忽略其他所有内容。classpath*ResourceBundleMessageSourcejava.util.ResourceBundle

我真的没有一个简单的解决方案给你。我认为你将不得不放弃并编写一个自定义实现(最有可能通过子类化),用于定位各种资源并通过接口公开它们。 不会有太大的帮助。ResourceBundleMessageSourceMessageSourceAbstractMessageSourcePathMatchingResourcePatternResolverMessageSourceResourceBundle


推荐