一尘不染

Spring MessageSource是否支持多个类路径?

spring

我正在使用Spring框架为基于Web的应用程序设计一个插件系统。插件是classpath上的jar。这样我就能获得诸如jsp之类的资源,请参见下文

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

到现在为止还挺好。但是我对messageSource有问题。在我看来,ReloadableResourceBundleMessageSource#setBasename不通过“ classpath *:” 支持多个类路径。如果仅使用“ classpath:”,则仅从一个插件获取messageSource。

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


阅读 943

收藏
2020-04-20

共2个答案

一尘不染

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

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

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

2020-04-20
一尘不染

通过@ 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-context.xml上,你必须具有classpath *:前缀

<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>
2020-04-20