2010-10-08 34 views
14

Tôi đang thiết kế một hệ thống plugin cho ứng dụng dựa trên web của chúng tôi bằng cách sử dụng khung công tác Spring. Plugins là lọ trên classpath. Vì vậy, tôi có thể nhận các nguồn như jsp, xem bên dướiSpring MessageSource có hỗ trợ nhiều đường dẫn lớp không?

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

Cho đến nay rất tốt. Nhưng tôi có một vấn đề với messageSource. Dường như với tôi rằng ReloadableResourceBundleMessageSource#setBasename không KHÔNG hỗ trợ nhiều đường dẫn lớp thông qua "classpath *:" Nếu tôi chỉ sử dụng "classpath:", tôi nhận được messageSource chỉ từ một plugin.

Có ai có ý tưởng cách đăng ký MessageSources từ tất cả các plugin không? Không tồn tại một thực hiện như vậy của MessageSource?

Trả lời

8

Vấn đề ở đây không phải với nhiều classpath hoặc trình nạp lớp, nhưng có bao nhiêu tài nguyên mà mã sẽ thử và tải cho một đường dẫn nhất định.

Cú pháp classpath* là cơ chế Spring, một cơ chế cho phép mã tải nhiều tài nguyên cho một đường dẫn nhất định. Rất tiện dụng. Tuy nhiên, ResourceBundleMessageSource sử dụng tiêu chuẩn java.util.ResourceBundle để tải tài nguyên và đây là cơ chế dumber đơn giản hơn nhiều, sẽ tải tài nguyên đầu tiên cho một đường dẫn nhất định và bỏ qua mọi thứ khác.

Tôi không thực sự dễ dàng sửa chữa cho bạn. Tôi nghĩ bạn sẽ phải bỏ qua ResourceBundleMessageSource và viết triển khai tùy chỉnh MessageSource (nhiều khả năng là phân lớp AbstractMessageSource) sử dụng PathMatchingResourcePatternResolver để tìm các tài nguyên khác nhau và hiển thị chúng thông qua giao diện MessageSource. ResourceBundle sẽ không giúp được gì nhiều.

+0

Cảm ơn! Đó là điều tôi lo lắng. – banterCZ

+0

Đối với một giải pháp hoạt động nhìn vào [câu trả lời của ajaristi] (http://stackoverflow.com/a/27532814/606662) –

9

Bạn có thể làm điều gì đó tương tự như dưới đây - về cơ bản chỉ định từng tên cơ sở có liên quan một cách rõ ràng.

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> 
     <property name="basenames"> 
      <list> 
       <value>classpath:com/your/package/source1</value> 
       <value>classpath:com/your/second/package/source2</value> 
       <value>classpath:com/your/third/package/source3/value> 
       <value>classpath:com/your/fourth/package/source4</value> 
      </list> 
     </property> 
    </bean> 
+5

Vâng, đúng vậy. Nhưng bạn phải biết tất cả các plugin trước. Các soulution nên phổ quát cho các plugin. – banterCZ

+4

Bạn chỉ cần dạy tôi cách nhập đường dẫn gói vào giá trị. –

2

Như thay thế, bạn có thể ghi đè lên refreshProperties phương pháp từ ReloadableResourceBundleMessageSource lớp như dưới đây Ví dụ:

public class MultipleMessageSource extends ReloadableResourceBundleMessageSource { 
    private static final String PROPERTIES_SUFFIX = ".properties"; 
    private PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 

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

và sử dụng nó với cấu hình bối cảnh mùa xuân như ReloadableResourceBundleMessageSource:

<bean id="messageSource" class="common.utils.MultipleMessageSource"> 
    <property name="basenames"> 
     <list> 
     <value>classpath:/messages/validation</value> 
     <value>classpath:/messages/messages</value> 
     </list> 
    </property> 
    <property name="fileEncodings" value="UTF-8"/> 
    <property name="defaultEncoding" value="UTF-8"/> 
    </bean> 

Tôi nghĩ rằng điều này sẽ làm các trick .

10

Với giải pháp của @ seralex-vi basenames/WEB-INF/tin nhắn không hoạt động.

tôi overwrited các refreshProperties phương pháp trên ReloadableResourceBundleMessageSource lớp Mà thực hiện cả hai loại basenames (classpath *: và/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); 
} 

Trên lò xo context.xml bạn phải có classpath *: prefix

<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> 
+5

Đây phải là câu trả lời, nó đưa ra một giải pháp và nó hoạt động. Cảm ơn – Don

0

Bạn có thể tận dụng lợi thế của cấu hình Java và nguồn thông báo phân cấp để xây dựng hệ thống plugin khá đơn giản. Trong mỗi lọ có thể cắm được, hãy thả một lớp như sau:

@Configuration 
public class MyPluginConfig { 
    @Bean 
    @Qualifier("external") 
    public HierarchicalMessageSource mypluginMessageSource() { 
     ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); 
     messageSource.setBasenames("classpath:my-plugin-messages"); 
     return messageSource; 
    } 
} 

và các tệp my-plugin-messages.properties tương ứng.

Trong lớp cấu hình ứng dụng Java chính đặt một cái gì đó như thế này:

@Configuration 
public class MainConfig { 
    @Autowired(required = false) 
    @Qualifier("external") 
    private List<HierarchicalMessageSource> externalMessageSources = Collections.emptyList(); 

    @Bean 
    public MessageSource messageSource() { 
     ReloadableResourceBundleMessageSource rootMessageSource = new ReloadableResourceBundleMessageSource(); 
     rootMessageSource.setBasenames("classpath:messages"); 

     if (externalMessageSources.isEmpty()) { 
      // No external message sources found, just main message source will be used 
      return rootMessageSource; 
     } 
     else { 
      // Wiring detected external message sources, putting main message source as "last resort" 
      int count = externalMessageSources.size(); 

      for (int i = 0; i < count; i++) { 
       HierarchicalMessageSource current = externalMessageSources.get(i); 
       current.setParentMessageSource(i == count - 1 ? rootMessageSource : externalMessageSources.get(i + 1)); 
      } 
      return externalMessageSources.get(0); 
     } 
    } 
} 

Nếu thứ tự của plugin là có liên quan, chỉ cần đặt @Order chú thích trong mỗi đậu nguồn tin pluggable.

Các vấn đề liên quan