dxyadc 2020-01-08
前面介绍了logback源码初始化过程是委托给ContextInitializer
void init() {
try {
try {
(new ContextInitializer(this.defaultLoggerContext)).autoConfig();
} catch (JoranException var2) {
Util.report("Failed to auto configure default logger context", var2);
}
if (!StatusUtil.contextHasStatusListener(this.defaultLoggerContext)) {
StatusPrinter.printInCaseOfErrorsOrWarnings(this.defaultLoggerContext);
}
this.contextSelectorBinder.init(this.defaultLoggerContext, KEY);
this.initialized = true;
} catch (Exception var3) {
Util.report("Failed to instantiate [" + LoggerContext.class.getName() + "]", var3);
}
}org.slf4j.impl.StaticLoggerBinder#init
->
ch.qos.logback.classic.util.ContextInitializer#autoConfig
public void autoConfig() throws JoranException {
/**
* <1>这里配置监听查找配置的消息
* 判断系统变量是否有-Dlogback.statusListenerClass 参数
* 等于SYSOUT 则默认使用OnConsoleStatusListener 这个是控制台打印
* 否则当做配置的全路径(我们自己创建一个StatusListener实现类)
*/
StatusListenerConfigHelper.installIfAsked(this.loggerContext);
/**
*这里会依次查找
* <2>1.从系统变量查找配置文件-Dlogback.configurationFile={file}
* 2.如果没有配置则依次找logback-test.xml logback.groovy logback.xml 找到任意一个返回
*/
URL url = this.findURLOfDefaultConfigurationFile(true);
if (url != null) {
//找到配置文件则走配置文件解析配置
this.configureByResource(url);
} else {
/**
* 这里主要是java的SPI扩展点ServiceLoader 如果想实现自己的配置文件定义 可以通过这个做扩展
*/
Configurator c = (Configurator) EnvUtil.loadFromServiceLoader(Configurator.class);
if (c != null) {
try {
c.setContext(this.loggerContext);
c.configure(this.loggerContext);
} catch (Exception var4) {
throw new LogbackException(String.format("Failed to initialize Configurator: %s using ServiceLoader", c != null ? c.getClass().getCanonicalName() : "null"), var4);
}
} else {
//没有SPI扩展 则使用默认的配置 SPI扩展可以参考介个
BasicConfigurator basicConfigurator = new BasicConfigurator();
basicConfigurator.setContext(this.loggerContext);
basicConfigurator.configure(this.loggerContext);
}
}
}<1>处主要是配置查找日志文件的监听器默认是控制台打印


<2>处

org.slf4j.impl.StaticLoggerBinder#init
->
ch.qos.logback.classic.util.ContextInitializer#autoConfig#configureByResource
public void configureByResource(URL url) throws JoranException {
if (url == null) {
throw new IllegalArgumentException("URL argument cannot be null");
} else {
String urlString = url.toString();
//如果配置文件是groovy结尾 按照groovy的解析防止 一般我们都是用xml所以不看这一步
if (urlString.endsWith("groovy")) {
if (EnvUtil.isGroovyAvailable()) {
GafferUtil.runGafferConfiguratorOn(this.loggerContext, this, url);
} else {
StatusManager sm = this.loggerContext.getStatusManager();
sm.add(new ErrorStatus("Groovy classes are not available on the class path. ABORTING INITIALIZATION.", this.loggerContext));
}
} else {
if (!urlString.endsWith("xml")) {
throw new LogbackException("Unexpected filename extension of file [" + url.toString() + "]. Should be either .groovy or .xml");
}
//如果是xml结尾则走xml的解析方式 委托给了JoranConfigurator
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(this.loggerContext);
configurator.doConfigure(url);
}
}
}
ch.qos.logback.core.joran.GenericConfigurator#doConfigure(java.net.URL)
public final void doConfigure(URL url) throws JoranException {
InputStream in = null;
boolean var12 = false;
String errMsg;
try {
var12 = true;
//暂时也不知道干啥的
informContextOfURLUsedForConfiguration(this.getContext(), url);
//获得一个连接对象 这里是FileURLConnection 可以想象是否可以支持http呢 就可以远程配置文件了
URLConnection urlConnection = url.openConnection();
//不使用缓存
urlConnection.setUseCaches(false);
//获取流
in = urlConnection.getInputStream();
//接下来看这个方法处理
this.doConfigure(in, url.toExternalForm());
var12 = false;
} catch (IOException var15) {
errMsg = "Could not open URL [" + url + "].";
this.addError(errMsg, var15);
throw new JoranException(errMsg, var15);
} finally {
if (var12) {
if (in != null) {
try {
in.close();
} catch (IOException var13) {
String errMsg = "Could not close input stream";
this.addError(errMsg, var13);
throw new JoranException(errMsg, var13);
}
}
}
}
if (in != null) {
try {
in.close();
} catch (IOException var14) {
errMsg = "Could not close input stream";
this.addError(errMsg, var14);
throw new JoranException(errMsg, var14);
}
}
}ch.qos.logback.core.joran.GenericConfigurator#doConfigure#doConfigure
public final void doConfigure(InputSource inputSource) throws JoranException {
long threshold = System.currentTimeMillis();
SaxEventRecorder recorder = new SaxEventRecorder(this.context);
//<1>这里利用Sax解析xml 并封装成SaxEvent
recorder.recordEvents(inputSource);
//<2>将封装成java对象的SaxEvent进行配置处理
this.doConfigure(recorder.saxEventList);
StatusUtil statusUtil = new StatusUtil(this.context);
if (statusUtil.noXMLParsingErrorsOccurred(threshold)) {
this.addInfo("Registering current configuration as safe fallback point");
this.registerSafeConfiguration(recorder.saxEventList);
}
}<1>
ch.qos.logback.core.joran.event.SaxEventRecorder#recordEvents
public List<SaxEvent> recordEvents(InputSource inputSource) throws JoranException {
SAXParser saxParser = this.buildSaxParser();
try {
//这里因为当前类继承了DefaultHandeler 所以通过这里将SAX解析成当前出席需要的对象
saxParser.parse(inputSource, this);
return this.saxEventList;
} catch (IOException var4) {
this.handleError("I/O error occurred while parsing xml file", var4);
} catch (SAXException var5) {
throw new JoranException("Problem parsing XML document. See previously reported errors.", var5);
} catch (Exception var6) {
this.handleError("Unexpected exception while parsing XML document.", var6);
}
}
//解析开始标签
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) {
String tagName = this.getTagName(localName, qName);
this.globalElementPath.push(tagName);
ElementPath current = this.globalElementPath.duplicate();
this.saxEventList.add(new StartEvent(current, namespaceURI, localName, qName, atts, this.getLocator()));
}
//解析结束标签
public void endElement(String namespaceURI, String localName, String qName) {
this.saxEventList.add(new EndEvent(namespaceURI, localName, qName, this.getLocator()));
this.globalElementPath.pop();
}<2>处代码
doConfigure
public void doConfigure(List<SaxEvent> eventList) throws JoranException {
//这里主要是初始化interpreter内部维护配置文件每个标签解析action的关系
this.buildInterpreter();
synchronized(this.context.getConfigurationLock()) {
//开始映射对应的action进行解析
this.interpreter.getEventPlayer().play(eventList);
}
}ch.qos.logback.core.joran.GenericConfigurator#buildInterpreter
protected void buildInterpreter() {
RuleStore rs = new SimpleRuleStore(this.context);
//添加action映射关系 action为对应标签的初始化方式 子类实现
this.addInstanceRules(rs);
this.interpreter = new Interpreter(this.context, rs, this.initialElementPath());
InterpretationContext interpretationContext = this.interpreter.getInterpretationContext();
interpretationContext.setContext(this.context);
this.addImplicitRules(this.interpreter);
this.addDefaultNestedComponentRegistryRules(interpretationContext.getDefaultNestedComponentRegistry());
}ch.qos.logback.classic.joran.JoranConfigurator
可以参考一下 实现自定义属性
public void addInstanceRules(RuleStore rs) {//父类路由 比如Appender就在父类追加的
super.addInstanceRules(rs);
rs.addRule(new ElementSelector("configuration"), new ConfigurationAction());
rs.addRule(new ElementSelector("configuration/contextName"), new ContextNameAction());
rs.addRule(new ElementSelector("configuration/contextListener"), new LoggerContextListenerAction());
rs.addRule(new ElementSelector("configuration/insertFromJNDI"), new InsertFromJNDIAction());
rs.addRule(new ElementSelector("configuration/evaluator"), new EvaluatorAction());
rs.addRule(new ElementSelector("configuration/appender/sift"), new SiftAction());
rs.addRule(new ElementSelector("configuration/appender/sift/*"), new NOPAction());
rs.addRule(new ElementSelector("configuration/logger"), new LoggerAction());
rs.addRule(new ElementSelector("configuration/logger/level"), new LevelAction());
rs.addRule(new ElementSelector("configuration/root"), new RootLoggerAction());
rs.addRule(new ElementSelector("configuration/root/level"), new LevelAction());
rs.addRule(new ElementSelector("configuration/logger/appender-ref"), new AppenderRefAction());
rs.addRule(new ElementSelector("configuration/root/appender-ref"), new AppenderRefAction());
rs.addRule(new ElementSelector("*/if"), new IfAction());
rs.addRule(new ElementSelector("*/if/then"), new ThenAction());
rs.addRule(new ElementSelector("*/if/then/*"), new NOPAction());
rs.addRule(new ElementSelector("*/if/else"), new ElseAction());
rs.addRule(new ElementSelector("*/if/else/*"), new NOPAction());
if (PlatformInfo.hasJMXObjectName()) {
rs.addRule(new ElementSelector("configuration/jmxConfigurator"), new JMXConfiguratorAction());
}
rs.addRule(new ElementSelector("configuration/include"), new IncludeAction());
rs.addRule(new ElementSelector("configuration/consolePlugin"), new ConsolePluginAction());
rs.addRule(new ElementSelector("configuration/receiver"), new ReceiverAction());
}具体扩展可以参考一下appender实现 当我们需要自定义某个组件的时候也需要看一下对应action源码 比如appenderAction 实现了某个接口就调用start方法 内部可能给我们预留很多扩展