logback的UNDEFINED_PROPERTY属性源码执行流程解读
作者:codecraft
序
本文主要研究一下logback的UNDEFINED_PROPERTY
substVars
ch/qos/logback/core/util/OptionHelper.java
public static String substVars(String input, PropertyContainer pc0, PropertyContainer pc1) { try { return NodeToStringTransformer.substituteVariable(input, pc0, pc1); } catch (ScanException e) { throw new IllegalArgumentException("Failed to parse input [" + input + "]", e); } }
OptionHelper提供了substVars方法,它执行NodeToStringTransformer的substituteVariable方法
substituteVariable
ch/qos/logback/core/subst/NodeToStringTransformer.java
public static String substituteVariable(String input, PropertyContainer pc0, PropertyContainer pc1) throws ScanException { Node node = tokenizeAndParseString(input); NodeToStringTransformer nodeToStringTransformer = new NodeToStringTransformer(node, pc0, pc1); return nodeToStringTransformer.transform(); }
substituteVariable方法则先根据input解析node,再创建NodeToStringTransformer,执行其transform方法
transform
ch/qos/logback/core/subst/NodeToStringTransformer.java
public String transform() throws ScanException { StringBuilder stringBuilder = new StringBuilder(); compileNode(node, stringBuilder, new Stack<Node>()); return stringBuilder.toString(); }
transform方法主要是执行compileNode,通过stringBuilder来收集变量值
compileNode
ch/qos/logback/core/subst/NodeToStringTransformer.java
private void compileNode(Node inputNode, StringBuilder stringBuilder, Stack<Node> cycleCheckStack) throws ScanException { Node n = inputNode; while (n != null) { switch (n.type) { case LITERAL: handleLiteral(n, stringBuilder); break; case VARIABLE: handleVariable(n, stringBuilder, cycleCheckStack); break; } n = n.next; } }
compileNode方法针对VARIABLE类型的执行handleVariable方法
handleVariable
ch/qos/logback/core/subst/NodeToStringTransformer.java
private void handleVariable(Node n, StringBuilder stringBuilder, Stack<Node> cycleCheckStack) throws ScanException { // Check for recursion if (haveVisitedNodeAlready(n, cycleCheckStack)) { cycleCheckStack.push(n); String error = constructRecursionErrorMessage(cycleCheckStack); throw new IllegalArgumentException(error); } cycleCheckStack.push(n); StringBuilder keyBuffer = new StringBuilder(); Node payload = (Node) n.payload; compileNode(payload, keyBuffer, cycleCheckStack); String key = keyBuffer.toString(); String value = lookupKey(key); // empty values are considered valid if (value != null) { Node innerNode = tokenizeAndParseString(value); compileNode(innerNode, stringBuilder, cycleCheckStack); cycleCheckStack.pop(); return; } // empty default literal is a valid value if (n.defaultPart == null) { stringBuilder.append(key + CoreConstants.UNDEFINED_PROPERTY_SUFFIX); cycleCheckStack.pop(); return; } Node defaultPart = (Node) n.defaultPart; StringBuilder defaultPartBuffer = new StringBuilder(); compileNode(defaultPart, defaultPartBuffer, cycleCheckStack); cycleCheckStack.pop(); String defaultVal = defaultPartBuffer.toString(); stringBuilder.append(defaultVal); }
handleVariable方法对于value为null,且defaultValue也为null的设置了默认值为key + CoreConstants.UNDEFINED_PROPERTY_SUFFIX)
UNDEFINED_PROPERTY_SUFFIX
public class CoreConstants { //...... public static final String UNDEFINED_PROPERTY_SUFFIX = "_IS_UNDEFINED"; }
UNDEFINED_PROPERTY_SUFFIX的值为_IS_UNDEFINED
小结
logback通过NodeToStringTransformer的handleVariable来获取变量值,若该value为null,且defaultValue也为null的设置了默认值为key + CoreConstants.UNDEFINED_PROPERTY_SUFFIX)
,即key_IS_UNDEFINED
,注意这里如果defaultValue不为null则不走IS_UNDEFINED的逻辑,即空字符串也是可以的。对于自定义appender需要注意一下appender属性的value处理逻辑。
以上就是logback的UNDEFINED_PROPERTY属性源码执行流程解读的详细内容,更多关于logback UNDEFINED_PROPERTY的资料请关注脚本之家其它相关文章!