美文网首页Spring
spring 如何动态加载properties文件

spring 如何动态加载properties文件

作者: Lisy_ | 来源:发表于2018-05-29 15:45 被阅读408次

    1. 在xml中配置properties路径

    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basenames">
            <list> <!-- 指定资源文件基名称 jdbc为文件名,不包含扩展名 -->
                <value>classpath:resource/jdbc</value>
            </list>
        </property>
    </bean>
    

    2. 获取WebApplicationContext(需要入参HttpServerletRequest request)

    ServletContext servletContext = request.getSession() .getServletContext();
    WebApplicationContext ctx = WebApplicationContextUtils .getRequiredWebApplicationContext(servletContext);
    

    3. tongguo WebApplicationContext获取中键值String msg = ctx.getMessage("jdbc.url",null,Locale.CHINA);

    Spring的MessageSource有两个常用的实现ReloadableResourceBundleMesssageSourceResourceBundleMessageSource.

    • ResourceBundleMessageSource:
    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="parentMessageSource" ref="bizMessageSource" />
        <property name = "basenames">
            <list>
                <value>resources.cls-web-resources</value>
                <value>resources.cls-web-resources-definitions</value>
                <value>resources.cls-web-resources-menu</value>
            </list>
        </property>
    </bean>
    
    • ReloadableResourceBundleMesssageSource
    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> 
        <property name="parentMessageSource" ref="bizMessageSource"/> 
        <property name="fallbackToSystemLocale">
            <value>false</value>
        </property> 
        <property name="basenames"> 
            <list>
                <value>classpath:resources/cls-web-resources</value>
                <value>classpath:resources/cls-web-resources-definitions</value> 
                <value>classpath:resources/cls-web-resources-menu</value>  
            </list> 
        </property>
    </bean>
    

    原因:因为ReloadableResourceBundleMessageSource的内部使用DefaultResourceLoader来装载ResourceBundle, 而ResourceBundleMessageSource内部是直接使用java.util.ResourceBundle.getBundle(String baseName,Locale locale, ClassLoader loader) 来获取i18n文件信息,而ResourceBundle是使用"."来作为basename分隔符的

    另外如果不设置"fallbackToSystemLocale"的话, 那么当传入的Locale是null或者ResourceBundle没有改Locale的配置文件的话, 那么会返回Locale.getDefault()的Locale下的Meseage. 该设置默认为True, 也就是说, 如果找不到相应的ResourceBundle, 系统始终会显示为中文的Resource, 建议关闭该设置, 否则fallBackLocale就没有什么意义了.

    另外还有一个有用的设置“useCodeAsDefaultMessage”,默认为false,这样当Spring在ResourceBundle中找不到messageKey的话,就抛出NoSuchMessageException,把它设置为True,则找不到不会抛出异常,而是使用messageKey作为返回值。

    spring中ResourceBundleMessageSource与ReloadableResourceBundleMessageSource查找资源的区别:

    1. ResourceBundleMessageSource在XML配置中无法指定编码,而ReloadableResourceBundleMessageSource可以指定编码

    2. 加载资源文件的方式不同:

      1. ResourceBundleMessageSource的加载,使用ClassUtils.getDefaultClassLoader()加载器,getDefaultClassLoader的方法代码如下:
      public static ClassLoader getDefaultClassLoader() { 
          ClassLoader cl = null;
          try { 
              cl = Thread.currentThread().getContextClassLoader();
          }catch (Throwable ex) {
              logger.debug("Cannot access thread context ClassLoader - falling back to system class loader", ex);
          } 
          if (cl == null){
              cl = ClassUtils.class.getClassLoader();
          }
          return cl; 
      }
      

      这种方式也是JVM默认的加载方式,先从当前线程中获取类加载器,如果没有,就获取这个类本身的类加载器

      1. ReloadableResourceBundleMessageSource默认也使用ClassUtils.getDefaultClassLoader()加载器,它加载资源的方式如下:
      public Resource getResource(String location){
          Assert.notNull(location, "Location must not be null");
          if (location.startsWith("classpath:")) {
              return new ClassPathResource(location.s string("classpath:".length()), getClassLoader()); 
          } 
          try{
              URL url = new URL(location);
              return new UrlResource(url);
          }catch (MalformedURLException ex){
              return getResourceByPath(location);
          }
      }
      
      1. 小结:ResourceBundleMessageSource从classloader中加载资源文件,可以看到:ReloadableResourceBundleMessageSource加载时,默认使用DefaultResourceLoader,他会先判断资源path是否带有classpath:前缀,如果有,用 ClassPathResource去加载资源文件,如果没有试着用文件协议的url去访问,再没有就在contextPath即WEB-INF下查找.
    3. 在项目中,MessageSource不会单独使用,通常我们会把它和自己的业务一起使用,这时候我们可以直接用它本身的方法,我们也可以在其中加入我们自己的逻辑:如,自定义的一个消息类:

    public class MessageSourceHelper { 
        private ResourceBundleMessageSource messageSource;
        public String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {
            String msg = messageSource.getMessage(code, args, defaultMessage, locale);
            return msg != null ? msg.trim() : msg;
        }
        public void setMessageSource(ResourceBundleMessageSource messageSource) {
            this.messageSource = messageSource;
        }
    } 
    

    在beans-message.xml中注入:

    <bean id="messageSourceHelper" class="com.myspring.message.MessageSourceHelper">
        <property name="messageSource">
            <ref local="messageSource" />
        </property>
    </bean> 
    
    1. 我们可以在MessageSourceHelper中加入自己的业务,注入依赖后,就可以在其他类中调用MessageSourceHelper中的方法。

    2. 理论简要:ApplicationContext接口扩展了MessageSource 接口,因而提供了消息处理的功能(i18n或者国际化)。与HierarchicalMessageSource一起使用,它还能够处理嵌套的消息,这些是Spring提供的处理消息的基本接口。让我们快速浏览一下它所定义的方法:

      • String getMessage(String code, Object[] args, String default, Locale loc):用来从MessageSource获取消息的基本方法。如果在指定的locale中没有找到消息,则使用默认的消息。args中的参数将使用标准类库中的MessageFormat来作消息中替换值。
      • String getMessage(String code, Object[] args, Locale loc):本质上和上一个方法相同,其区别在:没有指定默认值,如果没找到消息,会抛出一个NoSuhMessageException异常。
      • String getMessage(MessageSourceResolvable resolvable, Locale locale):上面方法中所使用的属性都封装到一个MessageSourceResolvable实现中,而本方法可以指定 MessageSourceResolvable实现。

    当一个ApplicationContext被加载时,它会自动在context中查找已定义为MessageSource类型的bean。此bean的名称须为messageSource。如果找到,那么所有对上述方法的调用将被委托给该 bean。否则ApplicationContext会在其父类中查找是否含有同名的bean。如果有,就把它作为MessageSource。如果它最终没有找到任何的消息源,一个空的StaticMessageSource将会被实例化,使它能够接受上述方法的调用。

    Spring目前提供了两个MessageSource的实现:ResourceBundleMessageSource和StaticMessageSource。它们都继承 NestingMessageSource以便能够处理嵌套的消息。StaticMessageSource很少被使用,但能以编程的方式向消息源添加消息。ResourceBundleMessageSource会用得更多一些

    相关文章

      网友评论

        本文标题:spring 如何动态加载properties文件

        本文链接:https://www.haomeiwen.com/subject/tirajftx.html