大数据 爬虫Python AI Sql玩转大数据大数据-简书

《Hadoop技术内幕深入解析Hadoop和HDFS》2.2.4

2018-09-28  本文已影响5人  程序员1

2.2.4 使用 get* 和 set* 访问 / 设置配置项

1. get*

get* 一共代表 21 个方法,它们用于在 Configuration 对象中获取相应的配置信息。这

些配置信息可以是 boolean(getBoolean)、int(getInt)、long(getLong)等基本类型,也

可以是其他一些 Hadoop 常用类型,如类的信息(getClassByName、getClasses、getClass)、

String 数 组(getStringCollection、getStrings)、URL(getResource) 等。 这 些 方 法 里 最

重要的是 get() 方法,它根据配置项的键获取对应的值,如果键不存在,则返回默认值

defaultValue。其他的方法都会依赖于 Configuration.get(),并在 get() 的基础上做进一步处

理。get() 方法如下:

public String get(String name, String defaultValue)

Configuration.get() 会调用 Configuration 的私有方法 substituteVars(),该方法会完成配置

的属性扩展。属性扩展是指配置项的值包含 ${key} 这种格式的变量,这些变量会被自动替

换成相应的值。也就是说,${key} 会被替换成以 key 为键的配置项的值。注意,如果 ${key}

替换后,得到的配置项值仍然包含变量,这个过程会继续进行,直到替换后的值中不再出现

变量为止。

substituteVars 的工作依赖于正则表达式:

varPat:\$\{[^\}\$ ]+\}

由于“$”、左花括号“{”、右花括号“}”都是正则表达式中的保留字,因此需要通过

“\”进行转义。正则表达式 varPat 中,“\$\{”部分用于匹配 ${key} 中的 key 前面的“${”,

最后的“\}”部分匹配属性扩展项的右花括号“}”,中间部分“[^\}\$ ]+”用于匹配属性扩展

键,它使用了两个正则表达式规则:

[^ ] 规则,通过 [^ ] 包含一系列的字符,使表达式匹配这一系列字符以外的任意一个 ❑

字符。也就是说,“[^\}\$ ]”将匹配除了“}”、“$”和空格以外的所有字符。注意,

$ 后面还包含了一个空格,这个看不见的空格,是通过空格的 Unicode 字符 \u0020 添

加到表达式中的。

+ 是一个修饰匹配次数的特殊符号,通过该符号保证了“+”前面的表达式“[^\}\$ ]” ❑

至少出现 1 次。

通过正则表达式“\$\{[^\}\$ ]+\}”,可以在输入字符串里找出需要进行属性扩展的地方,

并通过字符串替换,进行属性扩展。

前面提过,如果一次属性扩展完成以后,得到的表达式里仍然包含可扩展的变量,那

么,substituteVars() 需要再次进行属性扩展。考虑下面的情况:

属性扩展 ${key1} 的结果包含属性扩展 ${key2},而对 ${key2} 进行属性扩展后,产生

了一个包含 ${key1} 的新结果,这会导致属性扩展进入死循环,没办法停止。

针对这种可能发生的情况,substituteVars() 中使用了一个非常简单而又有效的策略,即

属性扩展只能进行一定的次数(20 次,通过 Configuration 的静态成员变量 MAX_SUBST 定

义),避免出现上面分析的属性扩展死循环。

最后一点需要注意的是,substituteVars() 中进行的属性扩展,不但可以使用保存在

Configuration 对象中的键 – 值对,而且还可以使用 Java 虚拟机的系统属性。如系统属

性 user.home 包含了当前用户的主目录,如果用户有一个配置项需要使用这个信息,可

以通过属性扩展 ${user.home},来获得对应的系统属性值。而且,Java 命令行可以通过

“-D=”的方式定义系统属性。这就提供了一个通过命令行,覆盖或者设置

Hadoop 运行时配置信息的方法。在 substituteVars() 中,属性扩展优先使用系统属性,然后

才是 Configuration 对象中保存的键 – 值对。具体代码如下:

// 正则表达式对象,包含正则表达式 \$\{[^\}\$ ]+\}

// 注意,u0020 前面只有一个”\”,转义发生在 Java 里,不在正则表达式里

private static Pattern varPat =

Pattern.compile("\\$\\{[^\\}\\$\u0020]+\\}");

// 最多做 20 次属性扩展

private static int MAX_SUBST = 20;

private String substituteVars(String expr) {

if (expr == null) {

return null;

}

Matcher match = varPat.matcher("");

String eval = expr;

// 循环,最多做 MAX_SUBST 次属性扩展

for(int s=0; s

match.reset(eval);

if (!match.find()) {

return eval; // 什么都没有找到,返回

}

String var = match.group();

var = var.substring(2, var.length()-1); // 获得属性扩展的键

String val = null;

try {

// 看看系统属性里有没有 var 对应的 val

// 这一步保证了我们首先使用系统属性做属性扩展

val = System.getProperty(var);

} catch(SecurityException se) {

LOG.warn("Unexpected SecurityException in Configuration", se);

}

if (val == null) {

// 看看 Configuration 保存的键 - 值对里有没有 var 对应的 val

val = getRaw(var);

}

if (val == null) {

// 属性扩展中的 var 没有绑定,不做扩展,返回

return eval;

}

// 替换 ${……},完成属性扩展

eval = eval.substring(0,match.start())

+val+eval.substring(match.end());

}

// 属性扩展次数过多,抛异常

throw new IllegalStateException(……);

}

2. set*

相对于 get* 来说,set* 的大多数方法都很简单,这些方法对输入进行类型转换等处理后,

最终都调用了下面的 Configuration.set() 方法:

public String set(String name, String value)

对 比 相 对 复 杂 的 Configuration.get(), 成 员 函 数 set() 只 是 简 单 地 调 用 了 成 员 变 量

properties 和 overlay 的 setProperty() 方法,保存传入的键 – 值对。

上一篇下一篇

猜你喜欢

热点阅读