首页 > 代码库 > How tomcat works 读书笔记十五 Digester库 下

How tomcat works 读书笔记十五 Digester库 下

在这一节里我们说说ContextConfig这个类。
这个类在很早的时候我们就已经使用了(之前那个叫SimpleContextConfig),但是在之前它干的事情都很简单,就是吧context里的configured变量置为true。在这里我们看看完整版的ContextConfig都干了什么。
在tomcat的实际部署中,StandContext类的实际监听器是org.apache.catalina.startup.ContextConfig的实例。
ContextConfig完成加载验证器阀,许可阀到StandContext的管道阀中。但最重要的就是应用上一节的Digester库,解析两个xml文件。一个是整个tomcat的配置文件,web.xml,在conf目录下。另一个是单个web应用的xml文件,在WEB-INF目录下。

在这里我主要说说如何让系统根据我们在某个web应用下的web.xml里面指定的那样,自动创建StandWrapper。
    LifecycleListener listener = new ContextConfig();
    ((Lifecycle) context).addLifecycleListener(listener);
  首先得在StandContext里注入ContextConfig这个监听器。

在StandContext的启动与关闭中,会触发以下的事件:
START_ENENT
STOP_ENENT
ContextConfig.java
 public void lifecycleEvent(LifecycleEvent event) {
        ...
        // Process the event that has occurred
        if (event.getType().equals(Lifecycle.START_EVENT))
            start();
        else if (event.getType().equals(Lifecycle.STOP_EVENT))
            stop();
    }
我们看看ContextConfig的start方法。
 private synchronized void start() {
    ...
        // Process the default and application web.xml files
        defaultConfig();          //解析conf/xml.xml
        applicationConfig();      //解析WEB-INF/web.xml
    ...
}
我们先不管整个tomcat的xml就看单个项目的:
 private void applicationConfig() {

       ...
        // Process the application web.xml file
        synchronized (webDigester) {
        //public static final String ApplicationWebXml = "/WEB-INF/web.xml";
                URL url =servletContext.getResource(Constants.ApplicationWebXml);

                InputSource is = new InputSource(url.toExternalForm());
                is.setByteStream(stream);
                webDigester.setDebug(getDebug());
                if (context instanceof StandardContext) {
                    ((StandardContext) context).setReplaceWelcomeFiles(true);
                }
                webDigester.clear();
                webDigester.push(context);//此时的栈里面就有context了
                webDigester.parse(is);  //开始解析
            }
    ...
    }
现在的问题是,那webDigester是怎么来的?
在ContextConfig中有下面的一个类变量。
private static Digester webDigester = createWebDigester();
我们看看createWebDigester
    private static Digester createWebDigester() {
        ...
        Digester webDigester = new Digester();
    ...
        webDigester.addRuleSet(new WebRuleSet());  //addRuleSet 对这个不清楚的看上一节
        return (webDigester);
    }
 现在我们就要去看WebRuleSet类了,还记得主要看哪个方法吗?
WebRuleSet.java
 public void addRuleInstances(Digester digester) {
    ....
         digester.addRule(prefix + "web-app/servlet",new WrapperCreateRule(digester));
    ...
    digester.addCallMethod(prefix + "web-app/servlet/servlet-class",
                              "setServletClass", 0);
        digester.addCallMethod(prefix + "web-app/servlet/servlet-name",
                              "setName", 0);
        digester.addCallMethod(prefix + "web-app/servlet-mapping",
                               "addServletMapping", 2);

    //setServletClass这个方法最后在哪里调用的? 请大家自己想一想
}

final class WrapperCreateRule extends Rule {

    public void begin(Attributes attributes) throws Exception {
        Context context =(Context) digester.peek(digester.getCount() - 1);
        Wrapper wrapper = context.createWrapper();
        digester.push(wrapper);
        if (digester.getDebug() > 0)
            digester.log("new " + wrapper.getClass().getName());
    }
}


大家看出流程了吗?
首先加入一个规则
digester.addRule(prefix + "web-app/servlet",new WrapperCreateRule(digester));
碰到web-app/servlet就调用begin方法,产生了一个wrapper。

web-app/servlet/servlet-name 碰到这个后,调用wrapper的那个方法就ok。




How tomcat works 读书笔记十五 Digester库 下