logback.xml自定义标签节点
问题
<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="com.example.user.log.DataMaskingPatternLayout">
<maskPattern>(\w+@\w+\.\w+)</maskPattern> <!-- Email -->
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</layout>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="console"/>
</root>
</configuration>
自定义layout
public class DataMaskingPatternLayout extends PatternLayout {
private List<String> maskPatterns = new ArrayList<>();
/**
* 标签属性的 set{TagName},add{TagName}, 都可以解析到标签
* 这里就可以自动 注入 <maskPattern/>标签
* @param maskPattern
*/
public void setMaskPattern(String maskPattern) {
maskPatterns.add(maskPattern);
}
}
今天的目的不是讨论自定义layout,而是如何接收自定义标签值
像这里,我们定义了<maskPattern>
标签,然后要接收这个标签内的值 ,不难发现,只要我们在对应的java代码中增加这个标签属性名称的 set或者add
方法名就可以了,这就很奇怪了,是怎么实现的呢?
原理
- 首先,logback会将自定义的结点封装成一个Action,而且是
ImplicitAction
- 然后在运行时取出对应的Action, 如果是属性值方式,则 通过
NestedBasicPropertyIA
实现类
//NestedBasicPropertyIA.java
public void body(InterpretationContext ec, String body) {
String finalBody = ec.subst(body);
// get the action data object pushed in isApplicable() method call
IADataForBasicProperty actionData = (IADataForBasicProperty) actionDataStack.peek();
switch (actionData.aggregationType) {
case AS_BASIC_PROPERTY:
actionData.parentBean.setProperty(actionData.propertyName, finalBody);
break;
case AS_BASIC_PROPERTY_COLLECTION:
actionData.parentBean.addBasicProperty(actionData.propertyName, finalBody);
break;
default:
addError("Unexpected aggregationType " + actionData.aggregationType);
}
}
交给 PropertySetter
public void setProperty(String name, String value) {
if (value == null) {
return;
}
Method setter = findSetterMethod(name);
if (setter == null) {
addWarn("No setter for property [" + name + "] in " + objClass.getName() + ".");
} else {
try {
setProperty(setter, name, value);
} catch (PropertySetterException ex) {
addWarn("Failed to set property [" + name + "] to value \"" + value + "\". ", ex);
}
}
}
//找到属性名称的方法
private Method findSetterMethod(String name) {
String propertyName = BeanUtil.toLowerCamelCase(name);
return beanDescription.getSetter(propertyName);
}
public class BeanDescription {
//propertyNameToGetter – map of property names to the associated getter.
//propertyNameToSetter – map of property names to the associated setter.
//propertyNameToAdder – map of property names to the associated adder.
private final Class<?> clazz;
private final Map<String, Method> propertyNameToGetter;
private final Map<String, Method> propertyNameToSetter;
private final Map<String, Method> propertyNameToAdder;
}
这里就可以发现,通过添加标签属性的 set或者add方法,就可以将自定义的标签内的值注入