tomcat7 源码学习笔记 2

在tomcat中Catalina类启动后,读取sever.xml初始化整个环境,此处使用了一个核心的工具类,搞定了这些,这个类是:Digester,此类继承自 jdk的DefaultHandler;

我们可以从一个简单的例子来窥视,此处使用server.xml的初始化原理,

Digester规则的设定是这样进行的,选取一组简单的代码如下:

digester.addObjectCreate("Server",
                                 "org.apache.catalina.core.StandardServer",
                                 "className");
        digester.addSetProperties("Server");
        digester.addSetNext("Server",
                            "setServer",
                            "org.apache.catalina.Server");

第一行addObjectCreate的详细内容是这样的:

public void addObjectCreate(String pattern, String className,
                                String attributeName) {

        addRule(pattern,
                new ObjectCreateRule(className, attributeName));

    }

内部ObjectCreateRule 实现了Rule接口的两个方法:
public void begin(String namespace, String name, Attributes attributes)
            throws Exception {

        // Identify the name of the class to instantiate
        String realClassName = className;
        if (attributeName != null) {
            String value = attributes.getValue(attributeName);
            if (value != null) {
                realClassName = value;
            }
        }
        if (digester.log.isDebugEnabled()) {
            digester.log.debug("[ObjectCreateRule]{" + digester.match +
                    "}New " + realClassName);
        }

        if (realClassName == null) {
            throw new NullPointerException("No class name specified for " +
                    namespace + " " + name);
        }

        // Instantiate the new object and push it on the context stack
        Class<?> clazz = digester.getClassLoader().loadClass(realClassName);
        Object instance = clazz.newInstance();
        digester.push(instance);
    }


 public void end(String namespace, String name) throws Exception {

        Object top = digester.pop();
        if (digester.log.isDebugEnabled()) {
            digester.log.debug("[ObjectCreateRule]{" + digester.match +
                    "} Pop " + top.getClass().getName());
        }

    }


所以在解析server.xml文件时,如果遇到Server标签,就会触发public void begin(String namespace, String name, Attributes attributes);



然后在内部利用反射,org.apache.catalina.core.StandardServer进行实例化。
如图:

第二行的:        digester.addSetProperties("Server");
也是注册了相应的规则:
public void addSetProperties(String pattern) {

        addRule(pattern,
                new SetPropertiesRule());

    }

在SetPropertiesRule中实现了  public void begin(String namespace, String theName, Attributes attributes)方法。
在其中有 

for (int i = 0; i < attributes.getLength(); i++) {
            String name = attributes.getLocalName(i);
            if ("".equals(name)) {
                name = attributes.getQName(i);
            }
            String value = attributes.getValue(i);
            .....


然后重要的在这里:
if (!digester.isFakeAttribute(top, name) 
                    && !IntrospectionUtils.setProperty(top, name, value) 
                    && digester.getRulesValidation()) 

其中:
IntrospectionUtils.setProperty(top, name, value) 


完成了对top对象中name属性设置值为value的动作,这样在server.xml中读取的对应标签的属

性就这样设置到对应的对象中。
第三行: 
digester.addSetNext("Server",
                            "setServer",
                            "org.apache.catalina.Server");

这种规则是这样设置的:
 public void addSetNext(String pattern, String methodName,
                           String paramType) {

        addRule(pattern,
                new SetNextRule(methodName, paramType));

    }

再看如下:
public void end(String namespace, String name) throws Exception {

        // Identify the objects to be used
        Object child = digester.peek(0);
        Object parent = digester.peek(1);
        if (digester.log.isDebugEnabled()) {
            if (parent == null) {
                digester.log.debug("[SetNextRule]{" + digester.match +
                        "} Call [NULL PARENT]." +
                        methodName + "(" + child + ")");
            } else {
                digester.log.debug("[SetNextRule]{" + digester.match +
                        "} Call " + parent.getClass().getName() + "." +
                        methodName + "(" + child + ")");
            }
        }

        // Call the specified method
        IntrospectionUtils.callMethod1(parent, methodName,
                child, paramType, digester.getClassLoader());
                
    }

在SetNextRule中只实现了end方法,所以在触发此方法时,调用parent方法中的methodName,设置值为child;
tomcat中的Catalina-->Server->Service->Connector这样的树状结构,正好xml文件的结构也类似如此,所以此处选用这种方法,以灵活的方式初始化整个环境,值得学习。

猜你喜欢

转载自chongquanyumo.iteye.com/blog/1798175
今日推荐