Catalina.createDigester方法詳細理解
這個方法主要設置(這個方法很重要,貴在理解,雖然還沒學過設計模式。。)
1、遇到<server>標簽時創建StandardServer實例
設置StandardServer類內部的相關屬性
並調用Catalina.setServer()方法設置server
2、遇到<Server>標簽的子標簽<Listener>==》對應匹配模式"Server/Listener"時
創建Listener實例,創建類名通過<Listener className=要創建的全類名(包名+類名)>獲取屬性className的值進行創建。
調用StandardServer的addLifecycleListener()為server添加監聽器
3、<Service>標簽時即匹配模式為:"Server/Service"創建StandardService實例,放入Stack棧中,調用addSetProperties方法為StandardService設置相關屬性
digester.addSetNext("Server/Service",
"addService",
"org.apache.catalina.Service");
調用Service的parent=stack.peek(1)即Server對象的addService方法為與Server關聯。
4、同2一樣為Service設置監聽器
5、<executor>標簽時即匹配模式:"Server/Service/Executor" 生成StandardThreadExecutor實例,
設置StandardThreadExecutor的屬性
調用其父類Service的addExecutor方法與Service關聯
6、調用addRule方法如上一樣,
pattern:"Server/Service/Connector"==>創建Connector實例,設置屬性,調用StandardService.addConnector()。為Connector設置監聽器
7、調用addRuleSet()方法
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/"));
跟6一樣
、、設置Engine
,EngineRuleSet(String prefix)當遇到模式為prefix + "Engine"即"Server/Service/Engine"會在EngineRuleSet.addRuleInstances()內部調用
addObjectCreate、addSetProperties、addRule這三個方法創建StandardEngine實例,設置屬性,調用Service。setContainer()方法。
創建SimpleTcpCluster實例調用Engine.setCluster()方法
給Engine添加監聽器,
創建realm對象實例,調用對應方法與Engine關聯。
創建AccessLogValve日誌對象(將日誌輸出到。txt文件),設置屬性,與engine關聯。
、、設置host
創建StandardHost,設置屬性,設置監聽器:HostConfig
調用Container。addChild()在這裏Container即與Engine相關聯
、、設置context
創建StandardContext,設置屬性,設置監聽器:ContextConfig
調用Container。addChild()在這裏Container即與Host相關聯
創建WebappLoader,與StandardContext關聯
創建StandardManager,與StandardContext關聯
創建store存儲類,與StandardContext關聯
創建StandardSessionIdGenerator,與StandardManager關聯
創建ApplicationParameter,與StandardContext關聯
創建realm對象實例,與StandardContext關聯
創建StandardRoot,與StandardContext關聯
context==》WebResourceRoot==StandardRoot設置
org.apache.catalina.webresources.StandardRoot提供各種resources實現類創建WebResourceSet,與StandardRoot關聯
(WebResourceSet的實現類有WarResourceSet、JarResourceSet、JarWarResourceSet、DirResourceSet、FileResourceSet等)
主要設置StandardRoot的preResources、jarResources、postResources這三個變量的實例
創建ContextResourceLink,與StandardContext關聯
創建AccessLogValve,與StandardContext關聯
創建StandardJarScanner,與StandardContext關聯
創建StandardJarScanFilter,與StandardJarScanner關聯
創建LegacyCookieProcessor,與StandardContext關聯
Note:上面已經說明完的具體對象被創建的整個過程,下面是對Digester的一些方法的理解。可以忽略!
protected Digester createStartDigester() { long t1=System.currentTimeMillis(); // Initialize the digester Digester digester = new Digester(); digester.setValidating(false); digester.setRulesValidation(true); HashMap<Class<?>, List<String>> fakeAttributes = new HashMap<>(); ArrayList<String> attrs = new ArrayList<>(); attrs.add("className"); fakeAttributes.put(Object.class, attrs); digester.setFakeAttributes(fakeAttributes); digester.setUseContextClassLoader(true); // Configure the actions we will be using 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.NamingResourcesImpl"); digester.addSetProperties("Server/GlobalNamingResources"); digester.addSetNext("Server/GlobalNamingResources", "setGlobalNamingResources", "org.apache.catalina.deploy.NamingResourcesImpl"); 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"); //Executor 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"); // Add RuleSets for nested elements 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/")); // When the ‘engine‘ is found, set the parentClassLoader. digester.addRule("Server/Service/Engine", new SetParentClassLoaderRule(parentClassLoader)); addClusterRuleSet(digester, "Server/Service/Engine/Cluster/"); long t2=System.currentTimeMillis(); if (log.isDebugEnabled()) { log.debug("Digester for server.xml created " + ( t2-t1 )); } return (digester); }
addObjectCreate()//Add an "object create" rule for the specified parameters.增加對象創建規則.遇到起始標簽的元素,初始化一個實例對象入棧
addSetProperties()//Add a "set properties" rule for the specified parameters.增加設置屬性規則.遇到某個屬性名,使用setter來賦值
如
digester.addSetProperties("Server");
對應標簽<Server port="8005" shutdown="SHUTDOWN">
遇到匹配模式為:Server。addSetProperties方法會反射調用StandardServer對象的setPort(int) 和setShutdown(String)兩個方法設置屬性
Digester.addSetNext(String pattern, String methodName, String paramType)//Add a "set next" rule for the specified parameters.增加set next規則.遇到下一標簽時的動作
即反射調用方法名為methodName的方法。
digester.addSetNext("Server",
"setServer",
"org.apache.catalina.Server");
當遇到<Server>標簽的下一標簽時被調用
addSetNext方法會調用SetNextRule.end()方法會調用這個當前top棧頂對象的parent父對象(棧頂對象的下一個元素)的setServer()方法
當StandardServer對象入棧後,棧中已經存在Catalina對象===>在Catalina.load()方法中設置了
所以StandardServer的parent父對象是Catalina,即調用Catalina.setServer()方法設置server屬性。
addRule:調用rule的begin 、body、end、finish方法來解析xml,入棧和出棧給對象賦值
addRuleSet:調用addRuleInstances來解析xml標簽
addObjectCreate(pattern ,className ,attributeName)
1、
Add an "object create" rule for the specified parameters為指定的參數增加一個對象創建規則.
- Parameters:
- pattern Element matching pattern元素匹配模式
- className Default Java class name to be created要創建的java類的名字
- attributeName Attribute name that optionally overrides the default Java class name to be created屬性名稱可以覆蓋要創建的默認Java類名稱
- 獲取xml文件中attributes屬性名為:className所對應的值替換第二個參數
-
ObjectCreateRule.java類的begin(String namespace, String name, Attributes attributes)方法,
這個方法將通過類名加載Class然後調用class.newInstance()生成類實例,最後放入digest的對象棧頂digester.push(instance);
String realClassName = className; if (attributeName != null) { String value = attributes.getValue(attributeName); if (value != null) { realClassName = value; } }
這個addObjectCreate()方法又調用addRule()方法
2、
Register a new Rule matching the specified pattern. This method sets the Digester
property on the rule.
- Parameters:
- pattern Element matching pattern
- rule Rule to be registered這裏的rule使用的是ObjectCreateRule
public void addRule(String pattern, Rule rule) { rule.setDigester(this);設置digester,將保存創建的對象的實例 getRules().add(pattern, rule);這裏將會返回Rules接口的實現類。然後再調用Rules.add()來添加Rule實例 }
Note:Rules:是一個接口public interface Rules
公共接口定義規則實例的集合(和相應的匹配模式)以及匹配策略的實現,
該策略選擇與解析期間發現的嵌套元素的特定模式匹配的規則。
Rule:是一個抽象類public abstract class Rule
ObjectCreateRule類的解釋
Rule implementation that creates a new object and pushes it onto the object stack. When the element is complete, the object will be popped
Rule實現類,創建一個新對象並將其推送到對象堆棧上。當元素完成時,對象將被彈出
3、RuleBase.add(pattern, rule)
public void add(String pattern, Rule rule) { // to help users who accidently add ‘/‘ to the end of their patterns int patternLength = pattern.length(); if (patternLength>1 && pattern.endsWith("/")) { pattern = pattern.substring(0, patternLength-1); } List<Rule> list = cache.get(pattern); if (list == null) { list = new ArrayList<>(); cache.put(pattern, list); } list.add(rule); rules.add(rule); if (this.digester != null) { rule.setDigester(this.digester); } if (this.namespaceURI != null) { rule.setNamespaceURI(this.namespaceURI); } }
上面方法用用HashMap<String, List<Rule>>類型變量cache存放pattern和Rule集合,用rules集合存放新加入的規則rules.add(rule)
Digester.addSetProperties(String pattern) 這個方法跟addObjectCreate方法調用相似順序如下 1addRule(pattern, new SetPropertiesRule()); 2getRules().add(pattern, rule); 3RulesBase.add(pattern, rule) Digester.addSetNext(String pattern, String methodName, String paramType) 1addRule(pattern, new SetNextRule(methodName, paramType)); 2getRules().add(pattern, rule); 3RulesBase.add(pattern, rule)註:
只有當遇到改元素的結束標簽時才會將改標簽代表的對象實例彈出棧。
Catalina.createDigester方法詳細理解