先上代码
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,留作后续使用