Tomcat源码走读 04-tomcat的server.xml解析

04-tomcat的server.xml解析

tomcat的server.xml的解析依靠的是Digester对象,入口在Catalina.load()中。

1.Digester digester = createStartDigester();

protected Digester createStartDigester() {
        Digester digester = new Digester();
        digester.setValidating(false);
        digester.setRulesValidation(true);
        HashMap<Class<?>, List<String>> fakeAttributes =
            new HashMap<Class<?>, List<String>>();
        ArrayList<String> attrs = new ArrayList<String>();
        attrs.add("className");
        fakeAttributes.put(Object.class, attrs);
        digester.setFakeAttributes(fakeAttributes);
        digester.setUseContextClassLoader(true);
        digester.addObjectCreate("Server",
                                 "org.apache.catalina.core.StandardServer",
                                 "className");
        digester.addSetProperties("Server");
        digester.addSetNext("Server",
                            "setServer",
                            "org.apache.catalina.Server");
        digester.addObjectCreate("Server/GlobalNamingResources",
                                 "org.apache.catalina.deploy.NamingResources");
        digester.addSetProperties("Server/GlobalNamingResources");
        digester.addSetNext("Server/GlobalNamingResources",
                            "setGlobalNamingResources",
                            "org.apache.catalina.deploy.NamingResources");
        digester.addObjectCreate("Server/Listener",
                                 null, // MUST be specified in the element
                                 "className");
        digester.addSetProperties("Server/Listener");
        digester.addSetNext("Server/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener");
        digester.addObjectCreate("Server/Service",
                                 "org.apache.catalina.core.StandardService",
                                 "className");
        digester.addSetProperties("Server/Service");
        digester.addSetNext("Server/Service",
                            "addService",
                            "org.apache.catalina.Service");
        digester.addObjectCreate("Server/Service/Listener",
                                 null, // MUST be specified in the element
                                 "className");
        digester.addSetProperties("Server/Service/Listener");
        digester.addSetNext("Server/Service/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener");
        digester.addObjectCreate("Server/Service/Executor",
                         "org.apache.catalina.core.StandardThreadExecutor",
                         "className");
        digester.addSetProperties("Server/Service/Executor");
        digester.addSetNext("Server/Service/Executor",
                            "addExecutor",
                            "org.apache.catalina.Executor");
        digester.addRule("Server/Service/Connector",
                         new ConnectorCreateRule());
        digester.addRule("Server/Service/Connector",
                         new SetAllPropertiesRule(new String[]{"executor"}));
        digester.addSetNext("Server/Service/Connector",
                            "addConnector",
                            "org.apache.catalina.connector.Connector");
        digester.addObjectCreate("Server/Service/Connector/Listener",
                                 null, // MUST be specified in the element
                                 "className");
        digester.addSetProperties("Server/Service/Connector/Listener");
        digester.addSetNext("Server/Service/Connector/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener");
        digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
        digester.addRuleSet(new EngineRuleSet("Server/Service/"));
        digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
        addClusterRuleSet(digester, "Server/Service/Engine/Host/Cluster/");
        digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));
        digester.addRule("Server/Service/Engine",
                         new SetParentClassLoaderRule(parentClassLoader));
        addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");
        return (digester);
    }

如上,主要是在指定digester的解析规则,下面我们就分析下上面的规则:

1.1 digester.addObjectCreate() ==> addRule(pattern,new ObjectCreateRule(className, attributeName));

主要是创建一个ObjectCreateRule对象创建规则,在digester解析过程中主要是调用rule对象的begin和end方法,begin处理开始标签,end处理闭合标签。所以我们主要是看这两个方法:

public void begin(String namespace, String name, Attributes attributes)
            throws Exception {
        String realClassName = className; //className就是我们创建ObjectCreateRule对象时传入的全类名
        if (attributeName != null) {
            String value = attributes.getValue(attributeName); //从server.xml的节点中获取attributeName属性的值
            if (value != null) {
                realClassName = value; //将该值赋值给realClassName 
            }
        }
        Class<?> clazz = digester.getClassLoader().loadClass(realClassName);
        Object instance = clazz.newInstance(); //创建指定的对象
        digester.push(instance); //把该对象压到digester的栈顶。
    }
public void end(String namespace, String name) throws Exception {
        Object top = digester.pop(); //出栈
    }

从上面可以知道ObjectCreateRule的作用就是读取指定的pattern节点创建节点指定的对象并在digester的stack中做压栈和出栈操作。

1.2 digester.addSetProperties() ==> addRule(pattern, new SetPropertiesRule());

创建一个属性赋值规则。他只有begin方法:

public void begin(String namespace, String theName, Attributes attributes)
            throws Exception {
        Object top = digester.peek(); //获取栈顶对象
        int attNamesLength = 0;
        if (attributeNames != null) {
            attNamesLength = attributeNames.length;
        }
        int propNamesLength = 0;
        if (propertyNames != null) {
            propNamesLength = propertyNames.length;
        }
        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);
            for (int n = 0; n<attNamesLength; n++) {
                if (name.equals(attributeNames[n])) {
                    if (n < propNamesLength) {
                        name = propertyNames[n];
                    } else {
                        name = null;
                    }
                    break;
                }
            } 
            if (!digester.isFakeAttribute(top, name) 
                    && !IntrospectionUtils.setProperty(top, name, value)  //从节点中获取指定的属性并赋值给对象
                    && digester.getRulesValidation()) {
            }
        }
    }

可以知道SetPropertiesRule的作用就是给对象赋值

1.3 digester.addSetNext() ==> addRule(pattern, new SetNextRule(methodName, paramType));

创建一个方法调用的规则。

public void end(String namespace, String name) throws Exception {
        Object child = digester.peek(0); //获取栈顶的对象
        Object parent = digester.peek(1); //获取栈顶下一个对象
        IntrospectionUtils.callMethod1(parent, methodName,
                child, paramType, digester.getClassLoader()); //用child做参数传入parent的指定方法中
    }

SetNextRule的作用就是指定父子的联系。

1.4 digester.addRule(“Server/Service/Connector”,new ConnectorCreateRule());添加connector对象创建规则。

public void begin(String namespace, String name, Attributes attributes)
            throws Exception {
        Service svc = (Service)digester.peek(); //获取栈顶对象,根据xml结构,connector的外层就是standardservice。
        Executor ex = null;
        if ( attributes.getValue("executor")!=null ) {
            ex = svc.getExecutor(attributes.getValue("executor")); //如果connector节点有executor属性的话获取该executor。
        }
        Connector con = new Connector(attributes.getValue("protocol")); //创建节点指定协议的connector对象
        if ( ex != null )  _setExecutor(con,ex);
        digester.push(con); //压栈
    }
    public void _setExecutor(Connector con, Executor ex) throws Exception {
        Method m = IntrospectionUtils.findMethod(con.getProtocolHandler().getClass(),"setExecutor",new Class[] {java.util.concurrent.Executor.class});
        if (m!=null) {
            m.invoke(con.getProtocolHandler(), new Object[] {ex});
        }else {
        }
    }
    public void end(String namespace, String name) throws Exception {
        digester.pop(); //出栈
    }

1.5 digester.addRule(“Server/Service/Connector”,new SetAllPropertiesRule(new String[]{“executor”})); 赋值Connector除了executor属性以外的属性

1.6 digester.addRuleSet() 批量添加规则。具体实现和上面差不多,这里以EngineRuleSet为例。

public void addRuleInstances(Digester digester) {
        digester.addObjectCreate(prefix + "Engine",
                                 "org.apache.catalina.core.StandardEngine",
        digester.addSetProperties(prefix + "Engine");
        digester.addRule(prefix + "Engine",
                         new LifecycleListenerRule
                         ("org.apache.catalina.startup.EngineConfig",
                          "engineConfigClass"));
        digester.addSetNext(prefix + "Engine",
                            "setContainer",
                            "org.apache.catalina.Container");
        digester.addObjectCreate(prefix + "Engine/Cluster",
                                 null, // MUST be specified in the element
                                 "className");
        digester.addSetProperties(prefix + "Engine/Cluster");
        digester.addSetNext(prefix + "Engine/Cluster",
                            "setCluster",
                            "org.apache.catalina.Cluster");
        digester.addObjectCreate(prefix + "Engine/Listener",
                                 null, // MUST be specified in the element
                                 "className");
        digester.addSetProperties(prefix + "Engine/Listener");
        digester.addSetNext(prefix + "Engine/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener");
        digester.addRuleSet(new RealmRuleSet(prefix + "Engine/"));
        digester.addObjectCreate(prefix + "Engine/Valve",
                                 null, // MUST be specified in the element
                                 "className");
        digester.addSetProperties(prefix + "Engine/Valve");
        digester.addSetNext(prefix + "Engine/Valve",
                            "addValve",
                            "org.apache.catalina.Valve");

    }

可以看到原理和上面都是一样的,只不过这里是批量添加规则。

2. 现在了解了digester的解析规则之后我们在回过头来看createStartDigester方法:

protected Digester createStartDigester() {
        digester.addObjectCreate("Server",
                                 "org.apache.catalina.core.StandardServer",
                                 "className"); //解析server节点,创建standardserver对象
        digester.addSetProperties("Server"); //因为这里面指定的属性名为空,所以实际什么都没做
        digester.addSetNext("Server",
                            "setServer",
                            "org.apache.catalina.Server"); //在Catalina.load()中在digester.parse()之前先压栈了catalina对象,所以这里获取的栈顶对象是刚压的server对象,栈顶下面的第一个是catalina对象,所以这里是调用catalina.setServer(server)。
        digester.addObjectCreate("Server/GlobalNamingResources",
                                 "org.apache.catalina.deploy.NamingResources"); //解析GlobalNamingResources节点,创建NamingResources对象
        digester.addSetProperties("Server/GlobalNamingResources");//什么都不做
        digester.addSetNext("Server/GlobalNamingResources",
                            "setGlobalNamingResources",
                            "org.apache.catalina.deploy.NamingResources"); //根据xml结构,此时的栈顶是standardserver,这是这里是调用standardserver.setGlobalNamingResources()。
        digester.addObjectCreate("Server/Listener",
                                 null, // MUST be specified in the element
                                 "className"); //解析Listener节点,因为这里没有个默认的className,所以这个节点必须指定className属性。
        digester.addSetProperties("Server/Listener");
        digester.addSetNext("Server/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener"); //同理调用StandardServer.addLifecycleListener(),添加server的生命周期监听
        digester.addObjectCreate("Server/Service",
                                 "org.apache.catalina.core.StandardService",
                                 "className"); //解析Service节点,创建StandardService对象。
        digester.addSetProperties("Server/Service");
        digester.addSetNext("Server/Service",
                            "addService",
                            "org.apache.catalina.Service"); //StandardServer.addService()
        digester.addObjectCreate("Server/Service/Listener",
                                 null, // MUST be specified in the element
                                 "className"); 
        digester.addSetProperties("Server/Service/Listener");
        digester.addSetNext("Server/Service/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener"); //standardservice.addLifecycleListener(),添加service的生命周期监听
        digester.addObjectCreate("Server/Service/Executor",
                         "org.apache.catalina.core.StandardThreadExecutor",
                         "className");
        digester.addSetProperties("Server/Service/Executor");
        digester.addSetNext("Server/Service/Executor",
                            "addExecutor",
                            "org.apache.catalina.Executor");
        digester.addRule("Server/Service/Connector",
                         new ConnectorCreateRule());
        digester.addRule("Server/Service/Connector",
                         new SetAllPropertiesRule(new String[]{"executor"}));
        digester.addSetNext("Server/Service/Connector",
                            "addConnector",
                            "org.apache.catalina.connector.Connector");
        digester.addObjectCreate("Server/Service/Connector/Listener",
                                 null, // MUST be specified in the element
                                 "className");
        digester.addSetProperties("Server/Service/Connector/Listener");
        digester.addSetNext("Server/Service/Connector/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener");
        digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
        digester.addRuleSet(new EngineRuleSet("Server/Service/"));
        digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
        addClusterRuleSet(digester, "Server/Service/Engine/Host/Cluster/");
        digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));
        digester.addRule("Server/Service/Engine",
                         new SetParentClassLoaderRule(parentClassLoader)); //设置Engine的parentClassLoader为catalina的parentClassLoader,也就是tomcat启动的时候设置给catalina的sharedLoader
        addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");
        return (digester);
    }

总结,从server.xml可以清楚的看到tomcat容器的结构和父子关系。而这个解析过程也是跟这个父子关系息息相关。在解析的过程中通过在digester里面进出栈来保证父子之间空间之间的联系。
1,Server,Service等节点解析规则中都有指定可以获取节点的className属性,也就是说我们如果不想用tomcat的StandardService等的话,可以自定义我们自己的Service,server等等,然后再相应的节点里面指定className属性为我们自定的类。
2,再解析的过程中通过各个父容器的addXXX()方法,使得父容器持有子容器的对象集合。
3,我们可以创建自己的LifecycleListener放在相应的节点里面来监听Server或者Service等的生命周期事件。
4,Engine的父类加载器被设置成了sharedLoader

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值