网站首页 > java教程 正文
1.PropertyPlaceholderHelper的作用
以下使用代码查看PropertyPlaceholderHelper类的作用
具体代码如下:
public class PropertyPlaceholderHelperSimpleApplication {
public static void main(String[] args) throws IOException {
//输入字符串
String a = "${name}";
String b = "${name${age}}";
//加载配置文件
InputStream is = PropertyPlaceholderHelperSimpleApplication.class.getClassLoader().getResourceAsStream("properties/simple.properties");
Properties properties = new Properties();
properties.load(is);
//初始化PropertyPlaceholderHelper
PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("${","}",":",false);
//helper的replacePlaceholders方法处理字符串
String result = helper.replacePlaceholders(a,properties);
System.out.println(result);
result = helper.replacePlaceholders(b,properties);
System.out.println(result);
}
}
其中配置文件simple.properties
name = poiuy
age = 31
name31 = jll
最后输出如下图,从输出中我们可以看到,PropertyPlaceholderHelper是将输入字符串中的文件进行替换处理,替换的逻辑是判断配置文件中是否有placeholderPrefix和placeholderSuffix包含的字符
2.PropertyPlaceholderHelper的使用
AbstractPropertyResolver的
resolveRequiredPlaceholders方法中,会用到PropertyPlaceholderHelper类来处理配置文件的路径
前三个参数分别和示例代码中一样
3.PropertyPlaceholderHelper源码解析
PropertyPlaceholderHelper的replacePlaceholders方法中,首先会创建一个
PropertyPlaceholderHelper.PlaceholderResolver的匿名内部类,然后调用replacePlaceholders方法
public class PropertyPlaceholderHelper {
public String replacePlaceholders(String value, Properties properties) {
Assert.notNull(properties, "'properties' must not be null");
properties.getClass();
return this.replacePlaceholders(value, properties::getProperty);
}
public String replacePlaceholders(String value, PropertyPlaceholderHelper.PlaceholderResolver placeholderResolver) {
Assert.notNull(value, "'value' must not be null");
return this.parseStringValue(value, placeholderResolver, (Set)null);
}
...
}
PlaceholderResolver是一个函数式接口,此处使用properties的getProperty方法来实现resolvePlaceholder的方法实现,
即调用resolvePlaceholder方法时实际上是获取Properties的属性
继续查看replacePlaceholders方法
public class PropertyPlaceholderHelper {
protected String parseStringValue(String value, PropertyPlaceholderHelper.PlaceholderResolver placeholderResolver, @Nullable Set visitedPlaceholders) {
//获取字符串中placeholderPrefix的下标
int startIndex = value.indexOf(this.placeholderPrefix);
//没有该前缀返回原字符串
if (startIndex == -1) {
return value;
} else {
//通过原字符串创建result对象
StringBuilder result = new StringBuilder(value);
//循环处理,知道找不到placeholderPrefix字符串
while(startIndex != -1) {
//从placeholderPrefix处开始查找placeholderSuffix的下标
int endIndex = this.findPlaceholderEndIndex(result, startIndex);
if (endIndex != -1) {
//截取字符串中placeholderPrefix到placeholderSuffix的字符
String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
String originalPlaceholder = placeholder;
if (visitedPlaceholders == null) {
visitedPlaceholders = new HashSet(4);
}
if (!((Set)visitedPlaceholders).add(placeholder)) {
throw new IllegalArgumentException("Circular placeholder reference '" + placeholder + "' in property definitions");
}
//对截取的q字符串递归处理,解决字符串中还有需要替代的字符
placeholder = this.parseStringValue(placeholder, placeholderResolver, (Set)visitedPlaceholders);
//从Properties中获取截取的字符串对应的value值,这里可以自定义实现类来处理
String propVal = placeholderResolver.resolvePlaceholder(placeholder);
//从Properties中获取的值为空且不是valueSeparator不是空
if (propVal == null && this.valueSeparator != null) {
//如果原字符串中有valueSeparator字符
int separatorIndex = placeholder.indexOf(this.valueSeparator);
if (separatorIndex != -1) {
//则截取valueSeparator之前的字符串
String actualPlaceholder = placeholder.substring(0, separatorIndex);
//valueSeparator后面的字符为默认值
String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
//从Proprties中获取actualPlaceholder对应的值,如果没有则返回默认值
propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
if (propVal == null) {
propVal = defaultValue;
}
}
}
//如果Properties中获取的值不为空
if (propVal != null) {
//对Properties中的value值递归处理
propVal = this.parseStringValue(propVal, placeholderResolver, (Set)visitedPlaceholders);
//原字符串中替换开始下标到结束下标的字符为获取到的value字符
result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
if (logger.isTraceEnabled()) {
//日志输出
logger.trace("Resolved placeholder '" + placeholder + "'");
}
//重新定义开始下标进行处理下一个字符
startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
} else {
//不是上面的两种情况,抛出不能处理异常
if (!this.ignoreUnresolvablePlaceholders) {
throw new IllegalArgumentException("Could not resolve placeholder '" + placeholder + "' in value \"" + value + "\"");
}
//重新定义开始下标对后面的字符进行处理
startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
}
((Set)visitedPlaceholders).remove(originalPlaceholder);
} else {
startIndex = -1;
}
}
//返回替换后的字符串
return result.toString();
}
}
...
}
4.Properties文件
了解了配置文件路径的解析过程,继续看下Spring中的Properties文件
AbstractPropertyResolver中Properties是通过getPropertyAsRawString方法获取,该方法在AbstractPropertyResolver中是抽象的,需要从子类中继续查看
在AbstractEnvironment的
resolveRequiredPlaceholders方法中会通过propertyResolver属性来调用
resolveRequiredPlaceholders方法
AbstractEnvironment的propertyResolver属性是
PropertySourcesPropertyResolver的实现类
public abstract class AbstractEnvironment implements ConfigurableEnvironment {
private final ConfigurablePropertyResolver propertyResolver;
public AbstractEnvironment() {
this.propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);
this.customizePropertySources(this.propertySources);
}
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
return this.propertyResolver.resolveRequiredPlaceholders(text);
}
...
}
PropertySourcesPropertyResolver是AbstractPropertyResolver的子类,在类中实现了getPropertyAsRawString方法
getPropertyAsRawString中调用getProperty方法,方法从PropertySources里面获取的
从上面可以看到,AbstractEnvironment创建
PropertySourcesPropertyResolver对象时,会传入PropertySources的引用,在AbstractEnvironment中,这个值通过customizePropertySources方法初始化
public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
@Nullable
private final PropertySources propertySources;
@Nullable
protected String getPropertyAsRawString(String key) {
return (String)this.getProperty(key, String.class, false);
}
@Nullable
protected T getProperty(String key, Class targetValueType, boolean resolveNestedPlaceholders) {
if (this.propertySources != null) {
Iterator var4 = this.propertySources.iterator();
//遍历propertySources
while(var4.hasNext()) {
PropertySource> propertySource = (PropertySource)var4.next();
if (this.logger.isTraceEnabled()) {
this.logger.trace("Searching for key '" + key + "' in PropertySource '" + propertySource.getName() + "'");
}
Object value = propertySource.getProperty(key);
if (value != null) {
if (resolveNestedPlaceholders && value instanceof String) {
value = this.resolveNestedPlaceholders((String)value);
}
this.logKeyFound(key, propertySource, value);
return this.convertValueIfNecessary(value, targetValueType);
}
}
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Could not find key '" + key + "' in any property source");
}
return null;
}
...
}
customizePropertySources方法在AbstractEnvironment的子类StandardEnvironment中实现
在方法中getSystemProperties和getSystemEnvironment方法分别添加系统属性和环境变量
public class StandardEnvironment extends AbstractEnvironment {
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
public StandardEnvironment() {
}
protected void customizePropertySources(MutablePropertySources propertySources) {
//System.getProperties();
propertySources.addLast(new PropertiesPropertySource("systemProperties", this.getSystemProperties()));
//System.getenv()
propertySources.addLast(new SystemEnvironmentPropertySource("systemEnvironment", this.getSystemEnvironment()));
}
}
这样可以在Spring配置文件中使用系统属性及环境变量,例如将配置文件放入到JAVA_HOME目录下,然后在Spring中使用Properties名,并用${}符号修饰,Spring在解析时首先会从systemProperties和systemEnvironment中查找该变量,最后在systemEnvironment中找到,并进行替换,最终的文件路径是环境变量与配置路径拼接得到
猜你喜欢
- 2025-04-09 使用SLF4J日志框架及相关的桥接模式
- 2025-04-09 OAuth2协议在Java应用中的优雅实现
- 2025-04-09 【Java面试题】MyBatis的工作原理
- 2025-04-09 新项目终于用上了jdk24(jdk发布)
- 2025-04-09 Java 中虚拟线程(线程虚拟化)
- 2025-04-09 小白都能看得懂的java虚拟机内存模型
- 2025-04-09 单个表上亿行数据的主键、索引设计,及分页查询
- 2025-04-09 Java这个高级特性,很多人还没用过
- 2025-04-09 Google Android ADB下载教程(谷歌ads安卓应用下载)
- 2025-04-09 超实用!Prompt程序员使用指南,大模型各角色代码实战案例分享
你 发表评论:
欢迎- 最近发表
-
- Java常量定义防暴指南:从"杀马特"到"高富帅"的华丽转身
- Java接口设计原则与实践:优雅编程的艺术
- java 包管理、访问修饰符、static/final关键字
- Java工程师的代码规范与最佳实践:优雅代码的艺术
- 编写一个java程序(编写一个Java程序计算并输出1到n的阶乘)
- Mycat的搭建以及配置与启动(mycat部署)
- Weblogic 安装 -“不是有效的 JDK Java 主目录”解决办法
- SpringBoot打包部署解析:jar包的生成和结构
- 《Servlet》第05节:创建第一个Servlet程序(HelloSevlet)
- 你认为最简单的单例模式,东西还挺多
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)