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