先上代碼
protected void initChain() throws ServletException { // Parse the configuration file specified by path or resource try { //還是先從servlet配置中找chainConfig //默認值是chainConfig = "org/apache/struts/chain/chain-config.xml"; String value; value = getServletConfig().getInitParameter("chainConfig"); if (value != null) { chainConfig = value; } ConfigParser parser = new ConfigParser(); List urls = splitAndResolvePaths(chainConfig); URL resource; for (Iterator i = urls.iterator(); i.hasNext();) { resource = (URL) i.next(); log.info("Loading chain catalog from " + resource); parser.parse(resource); } } catch (Exception e) { log.error("Exception loading resources", e); throw new ServletException(e); } }
這段代碼比較少,也比較簡單,就是解析chain-config.xml文件。(如果是多個文件,中間逗號分隔)
但是這個文件對struts的意義暫時還不是很清楚。(看字面的話,貌似是命令鏈條,用的裝飾器模式?)
chain-config.xml文件
<?xml version="1.0" ?> <catalog name="struts"> <define name="lookup" className="org.apache.commons.chain.generic.LookupCommand"/> <!-- ========== Servlet Complete Request Chain ========================= --> <chain name="servlet-standard"> <!-- Establish exception handling filter --> <command className="org.apache.struts.chain.commands.ExceptionCatcher" catalogName="struts" exceptionCommand="servlet-exception"/> <lookup catalogName="struts" name="process-action" optional="false"/> <lookup catalogName="struts" name="process-view" optional="false"/> </chain> <!-- ========== Action Processing chain ======================== --> <chain name="process-action"> <!-- Look up optional preprocess command --> <lookup catalogName="struts" name="servlet-standard-preprocess" optional="true"/> <command className="org.apache.struts.chain.commands.servlet.SelectLocale"/> <command className="org.apache.struts.chain.commands.servlet.SetOriginalURI"/> <command className="org.apache.struts.chain.commands.servlet.RequestNoCache"/> <command className="org.apache.struts.chain.commands.servlet.SetContentType"/> <command className="org.apache.struts.chain.commands.RemoveCachedMessages"/> <command className="org.apache.struts.chain.commands.servlet.SelectAction"/> <command className="org.apache.struts.chain.commands.servlet.AuthorizeAction"/> <command className="org.apache.struts.chain.commands.CreateActionForm"/> <command className="org.apache.struts.chain.commands.servlet.PopulateActionForm"/> <command className="org.apache.struts.chain.commands.servlet.ValidateActionForm"/> <command className="org.apache.struts.chain.commands.servlet.SelectInput"/> <command className="org.apache.struts.chain.commands.ExecuteCommand"/> <command className="org.apache.struts.chain.commands.servlet.SelectForward"/> <command className="org.apache.struts.chain.commands.SelectInclude"/> <command className="org.apache.struts.chain.commands.servlet.PerformInclude"/> <command className="org.apache.struts.chain.commands.servlet.CreateAction"/> <command className="org.apache.struts.chain.commands.servlet.ExecuteAction"/> </chain> <!-- ========== View Processing chain ======================== --> <chain name="process-view"> <command className="org.apache.struts.chain.commands.ExecuteForwardCommand"/> <command className="org.apache.struts.chain.commands.servlet.PerformForward"/> </chain> <chain name="servlet-exception"> <command className="org.apache.struts.chain.commands.servlet.ExceptionHandler"/> <command className="org.apache.struts.chain.commands.servlet.PerformForward"/> </chain> </catalog>
目測還是要從
ConfigParser
這個類入手
public class ConfigParser { private Digester digester = null; private RuleSet ruleSet = null; private boolean useContextClassLoader = true; public Digester getDigester() { if (digester == null) { digester = new Digester(); RuleSet ruleSet = getRuleSet(); digester.setNamespaceAware(ruleSet.getNamespaceURI() != null); digester.setUseContextClassLoader(getUseContextClassLoader()); digester.setValidating(false); digester.addRuleSet(ruleSet); } return (digester); } public RuleSet getRuleSet() { if (ruleSet == null) { ruleSet = new ConfigRuleSet(); } return (ruleSet); } public void setRuleSet(RuleSet ruleSet) { this.digester = null; this.ruleSet = ruleSet; } public boolean getUseContextClassLoader() { return (this.useContextClassLoader); } public void setUseContextClassLoader(boolean useContextClassLoader) { this.useContextClassLoader = useContextClassLoader; } public void parse(Catalog catalog, URL url) throws Exception { Digester digester = getDigester(); digester.clear(); digester.push(catalog); digester.parse(url); } public void parse(URL url) throws Exception { Digester digester = getDigester(); digester.clear(); digester.parse(url); } }
直接找到parse方法,好吧,三行,再看getDigester方法,好,裏面出現了RuleSet,目測解析就在這個
ConfigRuleSet裏面。
ConfigRuleSet代碼(各種setget被我去掉了)
public class ConfigRuleSet extends RuleSetBase { //貌似是分類、鏈條類?className也出現了,估計就是這裏 private String catalogClass = "org.apache.commons.chain.impl.CatalogBase"; private String catalogElement = "catalog"; private String chainClass = "org.apache.commons.chain.impl.ChainBase"; private String chainElement = "chain"; private String classAttribute = "className"; private String commandElement = "command"; private String defineElement = "define"; private String nameAttribute = "name"; public void addRuleInstances(Digester digester) { // catalog用ConfigCatalogRule處理,並且將成功處理的catalog放入CatalogFactory的一個map中,此map的key是catalog的classloader digester.addRule("*/" + getCatalogElement(), new ConfigCatalogRule(nameAttribute, catalogClass)); digester.addSetProperties("*/" + getCatalogElement()); //以下都是解析catalog的代碼 // 創建org.apache.commons.chain.impl.ChainBase這個類 //解析chain,三個參數,第一個是匹配表達式,第二個是默認創建類名稱,第三個是當匹配表達式所在的屬性來作爲類名 digester.addObjectCreate("*/" + getChainElement(), getChainClass(), getClassAttribute()); digester.addSetProperties("*/" + getChainElement()); //規則ConfigRegisterRule digester.addRule("*/" + getChainElement(), new ConfigRegisterRule(nameAttribute)); // Add rules for a command element digester.addObjectCreate("*/" + getCommandElement(), null, getClassAttribute()); digester.addSetProperties("*/" + getCommandElement()); digester.addRule("*/" + getCommandElement(), new ConfigRegisterRule(nameAttribute)); // Add rules for a define element digester.addRule("*/" + getDefineElement(), new ConfigDefineRule(getNameAttribute(), getClassAttribute())); } }
CatalogFactory將解析後的catalog放入自身map,留作後續使用