• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Java > .properties文件读取及占位符${...}替换源码解析

.properties文件读取及占位符${...}替换源码解析

作者:五月的仓颉 字体:[增加 减小] 来源:互联网 时间:2017-05-28

五月的仓颉 通过本文主要向大家介绍了properties 占位符,properties,properties是什么意思,log4j.properties,properties文件等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

前言

我们在开发中常遇到一种场景,Bean里面有一些参数是比较固定的,这种时候通常会采用配置的方式,将这些参数配置在.properties文件中,然后在Bean实例化的时候通过Spring将这些.properties文件中配置的参数使用占位符"${}"替换的方式读入并设置到Bean的相应参数中。

这种做法最典型的就是JDBC的配置,本文就来研究一下.properties文件读取及占位符"${}"替换的源码,首先从代码入手,定义一个DataSource,模拟一下JDBC四个参数:

public class DataSource {

  /**
   * 驱动类
   */
  private String driveClass;

  /**
   * jdbc地址
   */
  private String url;

  /**
   * 用户名
   */
  private String userName;

  /**
   * 密码
   */
  private String password;

  public String getDriveClass() {
    return driveClass;
  }

  public void setDriveClass(String driveClass) {
    this.driveClass = driveClass;
  }

  public String getUrl() {
    return url;
  }

  public void setUrl(String url) {
    this.url = url;
  }

  public String getUserName() {
    return userName;
  }

  public void setUserName(String userName) {
    this.userName = userName;
  }

  public String getPassword() {
    return password;
  }

  public void setPassword(String password) {
    this.password = password;
  }

  @Override
  public String toString() {
    return "DataSource [driveClass=" + driveClass + ", url=" + url + ", userName=" + userName + ", password=" + password + "]";
  }
}

</div>

定义一个db.properties文件:

 driveClass=0
 url=1
 userName=2
 password=3
</div>

定义一个properties.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:aop="http://www.springframework.org/schema/aop"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

  <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="properties/db.properties"></property>
  </bean> 

  <bean id="dataSource" class="org.xrq.spring.action.properties.DataSource">
    <property name="driveClass" value="${driveClass}" />
    <property name="url" value="${url}" />
    <property name="userName" value="${userName}" />
    <property name="password" value="${password}" />
  </bean>
</beans>
</div>

写一段测试代码:

public class TestProperties {

  @Test
  public void testProperties() {
    ApplicationContext ac = new ClassPathXmlApplicationContext("spring/properties.xml");

    DataSource dataSource = (DataSource)ac.getBean("dataSource");
    System.out.println(dataSource);
  }
}
</div>

运行结果就不贴了,很明显,下面就来分析一下Spring是如何将properties文件中的属性读入并替换"${}"占位符的。

PropertyPlaceholderConfigurer类解析

在properties.xml文件中我们看到了一个类PropertyPlaceholderConfigurer,顾名思义它就是一个属性占位符配置器,看一下这个类的继承关系图:

看到从这张图上,我们能分析出来的最重要的一点就是PropertyPlaceholderConfigurer是BeanFactoryPostProcessor接口的实现类,想见Spring上下文必然是在Bean定义全部加载完毕后且Bean实例化之前通过postProcessBeanFactory方法一次性地替换了占位符"${}"。

.properties文件读取源码解析

下面来看一下postProcessBeanFactory方法实现:

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  try {
    Properties mergedProps = mergeProperties();

    // Convert the merged properties, if necessary.
    convertProperties(mergedProps);
    // Let the subclass process the properties.
    processProperties(beanFactory, mergedProps);
  }
  catch (IOException ex) {
    throw new BeanInitializationException("Could not load properties", ex);
  }
}

</div>

跟一下第3行的mergeProperties方法:

protected Properties mergeProperties() throws IOException {
  Properties result = new Properties();

  if (this.localOverride) {
    // Load properties from file upfront, to let local properties override.
    loadProperties(result);
  }

  if (this.localProperties != null) {
    for (Properties localProp : this.localProperties) {
      CollectionUtils.mergePropertiesIntoMap(localProp, result);
    }
  }

  if (!this.localOverride) {
    // Load properties from file afterwards, to let those properties override.
    loadProperties(result);
  }
  return result;
}

</div>

第2行的方法new出一个Properties,名为result,这个result会随着之后的代码传入,.properties文件中的数据会写入result中。

OK,接着看,代码进入第17行的方法,通过文件加载.properties文件:

protected void loadProperties(Properties props) throws IOException {
  if (this.locations != null) {
    for (Resource location : this.locations) {
      if (logger.isInfoEnabled()) {
        logger.info("Loading properties file from " + location);
      }
      InputStream is = null;
      try {
        is = location.getInputStream();

        String filename = null;
        try {
          filename = location.getFilename();
        } catch (IllegalStateException ex) {
          // resource is not file-based. See SPR-7552.
        }

        if (filename != null && filename.endsWith(XML_FILE_EXTENSION)) {
          this.propertiesPersister.loadFromXml(props, is);
        }
        else {
          if (this.fileEncoding != null) {
            this.propertiesPersister.load(props, new InputStreamReader(is, this.fileEncoding));
          }
          else {
            this.propertiesPersister.load(props, is);
          }
        }
      }
      catch (IOException ex) {
        if (this.ignoreResourceNotFound) {
          if (logger.isWarnEnabled()) {
            logger.warn("Could not load properties from " + location + ": " + ex.getMessage());
          }
        }
        else {
          throw ex;
        }
      }
      finally {
        if (is != null) {
          is.close();
        }
      }
    }
  }
}

</div>

第9行,PropertyPlaceholderConfigurer的配置可以传入路径列表(当然这里只传了一个db.properties),第3行遍历列表,第9行通过一个输入字节流InputStream获取.properties对应的二进制数据,然后第23行的代码将InputStream中的二进制解析,写入第一个参数Properties中,Properties是JDK原生的读取.properties文件的工具。

就这样一个简单的流程,将.properties中的数据进行了解析,并写入result中(result是mergeProperties方法中new出的一个Properties)。

占位符"${...}"替换源码解析

上面看了.properties文件读取流程,接着就应当替换"${}"占位符了,还是回到postProcessBeanFactory方法:

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  try {
    Properties mergedProps = mergeProperties();

    // Convert the merged properties, if necessary.
    convertProperties(mergedProps);
    // Let the subclass process the properties.
   



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • .properties文件读取及占位符${...}替换源码解析
  • .properties文件读取及占位符${...}替换源码解析

相关文章

  • 2017-05-28SpringMVC实现自定义类型转换器
  • 2017-05-28Java Socket编程(一) Socket传输模式
  • 2017-05-28Java中ArrayList的工作原理详解
  • 2017-05-28Java实现单链表翻转实例代码
  • 2017-05-28Spring Data JPA 复杂/多条件组合分页查询
  • 2017-05-28JVM(Java虚拟机)简介(动力节点Java学院整理)
  • 2017-05-28Struts2拦截器登录验证实例
  • 2017-05-28SWT(JFace) 简易浏览器 制作实现代码第1/2页
  • 2017-05-28Java 中IO流字符流详解及实例
  • 2017-05-28java 使用ImageIO.writer从BufferedImage生成jpeg图像遇到问题总结及解决

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • SWT(JFace)体验之复制粘贴
    • Java自定义异常_动力节点Java学院整理
    • Java 反射机制详解及实例
    • JBoss arjuna TransactionReaper不回滚超时
    • RandomAccessFile简介_动力节点Java学院整理
    • Java微信公众平台开发(13) 微信JSSDK中Config配置
    • JAVA用户自定义事件监听实例代码
    • 详解在SpringBoot应用中获取应用上下文方法
    • 详解springboot + profile(不同环境读取不同配置)
    • spring boot整合RabbitMQ实例详解(Fanout模式)

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有