logback.xml自定义标签节点
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.javapublic void body(InterpretationContext ec, String body) {String finalBody = ec.subst(body);// get the action data object pushed in isApplicable() method callIADataForBasicProperty 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方法,就可以将自定义的标签内的值注入