读logback源码系列文章(七)——配置的实际工作类Action
上篇博客介绍了ContextInitializer类如何把框架的配置工作委托给各个Action具体实现类,这篇博客就接下来介绍一下,Action组件是如何进行配置的实际工作的
老规矩,先上图
如图所示,首先Action是一个抽象类,定义了begin()、body()、end()方法,这些方法如上篇博客所说,是给Interpreter调用的,Interpreter的endElement()方法会调用private的callEndAction()方法,然后callEndAction()方法调用实际Action的end()方法
然后针对GenericConfigurator中addInstanceRules()方法定义的每种元素,比如<appender>、<appender-ref>,都有一个对应的Action,负责对这种元素进行处理
Action组件的类别是很多的,比较常见的有LoggerAction、AppenderAction、AppenderRefAction等,下面就以AppenderAction和AppenderRefAction为例子,来说明Action的工作方式
public void begin(InterpretationContext ec, String localName, Attributes attributes) throws ActionException { // We are just beginning, reset variables appender = null; inError = false; String className = attributes.getValue(CLASS_ATTRIBUTE); if (OptionHelper.isEmpty(className)) { addError("Missing class name for appender. Near [" + localName + "] line " + getLineNumber(ec)); inError = true; return; } try { addInfo("About to instantiate appender of type [" + className + "]"); appender = (Appender) OptionHelper.instantiateByClassName(className, ch.qos.logback.core.Appender.class, context); appender.setContext(context); String appenderName = ec.subst(attributes.getValue(NAME_ATTRIBUTE)); if (OptionHelper.isEmpty(appenderName)) { addWarn("No appender name given for appender of type " + className + "]."); } else { appender.setName(appenderName); addInfo("Naming appender as [" + appenderName + "]"); } // The execution context contains a bag which contains the appenders // created thus far. HashMap<String, Appender> appenderBag = (HashMap) ec.getObjectMap().get( ActionConst.APPENDER_BAG); // add the appender just created to the appender bag. appenderBag.put(appenderName, appender); ec.pushObject(appender); } catch (Exception oops) { inError = true; addError("Could not create an Appender of type [" + className + "].", oops); throw new ActionException(oops); } }<appender name="ma" />
public static Object instantiateByClassName(String className, Class superClass, Context context) throws IncompatibleClassException, DynamicClassLoadingException { ClassLoader classLoader = Loader.getClassLoaderOfObject(context); return instantiateByClassName(className, superClass, classLoader); }public static Object instantiateByClassName(String className, Class superClass, ClassLoader classLoader) throws IncompatibleClassException, DynamicClassLoadingException { if (className == null) { throw new NullPointerException(); } try { Class classObj = null; classObj = classLoader.loadClass(className); if (!superClass.isAssignableFrom(classObj)) { throw new IncompatibleClassException(superClass, classObj); } return classObj.newInstance(); } catch (IncompatibleClassException ice) { throw ice; } catch (Throwable t) { throw new DynamicClassLoadingException("Failed to instantiate type " + className, t); } }public void begin(InterpretationContext ec, String tagName, Attributes attributes) { // Let us forget about previous errors (in this object) inError = false; // logger.debug("begin called"); Object o = ec.peekObject(); if (!(o instanceof AppenderAttachable)) { String errMsg = "Could not find an AppenderAttachable at the top of execution stack. Near [" + tagName + "] line " + getLineNumber(ec); inError = true; addError(errMsg); return; } AppenderAttachable appenderAttachable = (AppenderAttachable) o; String appenderName = ec.subst(attributes.getValue(ActionConst.REF_ATTRIBUTE)); if (OptionHelper.isEmpty(appenderName)) { // print a meaningful error message and return String errMsg = "Missing appender ref attribute in <appender-ref> tag."; inError = true; addError(errMsg); return; } HashMap appenderBag = (HashMap) ec.getObjectMap().get( ActionConst.APPENDER_BAG); Appender appender = (Appender) appenderBag.get(appenderName); if (appender == null) { String msg = "Could not find an appender named [" + appenderName + "]. Did you define it below in the config file?"; inError = true; addError(msg); addError("See " + CoreConstants.CODES_URL + "#appender_order for more details."); return; } addInfo("Attaching appender named [" + appenderName + "] to " + appenderAttachable); appenderAttachable.addAppender(appender); }