2010-10-08 14 views
14

Web tabanlı uygulamamız için Bahar çerçevesini kullanarak bir eklenti sistemi tasarlıyorum. Eklentiler, sınıf yolunda kavanozdur. Bu yüzden jsp gibi kaynakları alabildim, şu ana kadar çok iyi görüyoruz. Ama messageSource ile ilgili bir sorunum var. ReloadableResourceBundleMessageSource#setBasenamearacılığıyla birden sınıf yolunu DESTEKLEMEZ geliyor bana "sınıf yolunda *:" Ben sadece kullanırsanız "sınıfyolu:" Ben sadece tek eklentisinden messageSource olsun.Spring MessageSource Çoklu Sınıf Yolunu Destekliyor mu?

herkesin tüm eklentileri messageSources kayıt nasıl bir fikir var mı? MessageSource'un böyle bir uygulaması var mı?

cevap

8

burada mesele değildir çoklu Sınıf yollarıyla veya classloaders ile ancak kod belirli bir yol denemek ve yük kaç kaynaklar beraberdir.

classpath* sözdizimi bir yay mekanizması, belirli bir yol için birden fazla kaynak yüklemek için bir kod mümkün kılar. Çok kullanışlı. Ancak, ResourceBundleMessageSource, kaynakları yüklemek için java.util.ResourceBundle standardını kullanır ve bu, belirli bir yol için ilk kaynağı yükleyecek ve diğer her şeyi göz ardı edecek çok daha basit, bir araç mekanizmasıdır.

Gerçekten sizin için kolay bir düzeltme yok. Ben ResourceBundleMessageSource hendek ve MessageSource (büyük olasılıkla AbstractMessageSource alt sınıflandırma tarafından özel bir uygulama) PathMatchingResourcePatternResolver kullanarak çeşitli kaynakları bulmak ve MessageSource arabirim aracılığıyla bunları göstermek için kullanacağız sanırım. ResourceBundle çok fazla yardımcı olmayacak.

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); 
    } 
} 

ve ReloadableResourceBundleMessageSource gibi bahar bağlam yapılandırma ile kullanmak:

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

ben bu hileyi yapmak gerektiğini düşünüyorum örneğin aşağıda gibi refreshProperties yöntem sınıf ReloadableResourceBundleMessageSource dan geçersiz olabilir alternatif olarak

+0

Teşekkürler! Endişelendiğim bir şey. – banterCZ

+0

[ajaristi'nin cevabı] 'na bakarak çalışan bir çözüm için (http://stackoverflow.com/a/27532814/606662) –

9

Aşağıda benzer bir şey yapabileceğini - esasen açıkça ilgili her basename belirtin.

<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

Evet, doğru. Ama tüm eklentileri önceden bilmelisiniz. Ruh hali eklentiler için evrensel olmalıdır. – banterCZ

+4

Sadece paket yollarının değerlere nasıl girileceğini öğrettiniz. –

2

, . @ Solüsyonu ile

10

seralex-vi basenames/WEB INF/mesajlar görev.

Sınıf ReloadableResourceBundleMessageSource üzerinde yöntem refreshProperties overwrited basenames her iki türünü gerçekleştirmek wich: bahar-context.xml Açık (sınıf yolu * ve/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); 
} 

Eğer sınıf yolunu olmalıdır *: öneki

<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

Bu cevap olmalı, bir çözüm veriyor ve çalışıyor. Teşekkürler – Don

0

Java yapılandırma ve hiyerarşik mesaj kaynaklardan oldukça basit eklenti sistemi oluşturmak için yararlanabilir. Her takılabilir kavanozda böyle bir sınıftan:

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

ve ilgili my-plugin-messages.properties dosyaları.Sadece her takılabilir ileti kaynağı fasulye @Order açıklamalar eklediniz,

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

eklentileri sırası alakalı ise: Ana uygulama Java yapılandırma sınıfta

böyle bir şey koydu.