先做个铺垫,先回忆一下ActionServlet.initChain的细节
public void addRuleInstances(Digester digester) {
// Add rules for a catalog element
digester.addRule("*/" + getCatalogElement(),
new ConfigCatalogRule(nameAttribute, catalogClass));
digester.addSetProperties("*/" + getCatalogElement());
// Add rules for a chain element
digester.addObjectCreate("*/" + getChainElement(),
getChainClass(),
getClassAttribute());
digester.addSetProperties("*/" + getChainElement());
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
<span style="white-space:pre"> </span>//getNameAttribute()实际的值是"name",后面那个参数是"className"
digester.addRule("*/" + getDefineElement(),
new ConfigDefineRule(getNameAttribute(),
getClassAttribute()));
}
这里面有个特别的地方,在于define标签的处理。看ConfigDefineRule.begin代码
public void begin(String namespace, String name, Attributes attributes)
throws Exception {
// Extract the actual name and implementation class to use
<span style="white-space:pre"> </span>//获取name属性值
String nameValue = attributes.getValue(nameAttribute);
<span style="white-space:pre"> </span>//获取className属性值chain-config.xml
String classValue = attributes.getValue(classAttribute);
//默认情况下org/apache/struts/chain/chain-config.xml<define name="lookup" className="org.apache.commons.chain.generic.LookupCommand"/>
digester.addObjectCreate("*/" + nameValue, classValue);
digester.addSetProperties("*/" + nameValue);
digester.addRule("*/" + nameValue,
new ConfigRegisterRule(nameAttribute));
}
org.apache.commons.chain.generic.LookupCommand
LookupCommand)
1、init方法
public void init(ActionServlet servlet, ModuleConfig moduleConfig)
throws ServletException {
LOG.info(
"Initializing composable request processor for module prefix '"
+ moduleConfig.getPrefix() + "'");
//清空actions,然后赋值servlet和moduleConfig
super.init(servlet, moduleConfig);
//赋值,this.catalogFactory = CatalogFactory.getInstance();
initCatalogFactory(servlet, moduleConfig);
//拿到ControllerConfig配置
ControllerConfig controllerConfig = moduleConfig.getControllerConfig();
//这个默认值是struts
String catalogName = controllerConfig.getCatalog();
/* CatalogFactory.getInstance().getCatalog
* 这个在catalogFactory实际上是在ActionServlet.init中的initChain来赋值初始化的
* 在ActionServlet.initChain中,解析xml时,会根据catalog标签生成一个org.apache.commons.chain.impl.CatalogBase。
* 而catalogFactory中有两个属性一个是catalog,另一个是catalogs(Map),这两个属性专门存放这些
* CatalogBase对象,其中没有name的会放在catalog,有name的则以键值对的形式放入catalogs中
*/
catalog = this.catalogFactory.getCatalog(catalogName);
if (catalog == null) {
throw new ServletException("Cannot find catalog '" + catalogName
+ "'");
}
//默认值是servlet-standard
String commandName = controllerConfig.getCommand();
/*
* 找到名字是servlet-standard的command
* 回忆一下,在Action.initChain中,碰到chain标签时会这样解析。
* 1、 digester.addObjectCreate生成org.apache.commons.chain.impl.ChainBase对象
* 2、 digester.addSetProperties给对象属性赋值
* 3、 digester.addRule(/chain",new ConfigRegisterRule(nameAttribute));
* 其中rule,是这样处理的。拿到刚刚生成的ChainBase,和在digester栈中ChainBase的前一个对象(称之为next对象),
* 接着调用next.addCommand方法,ChainBase作为参数
* 这个next必须实现Command接口
* 但是,如果这个next是Catalog,那么调用的是addCommand(name,chainBase),
* 如果next是ChainBase对象,那么调用addCommand(chainBase)
* 差别就在于有没name
*
*/
command = catalog.getCommand(commandName);
if (command == null) {
throw new ServletException("Cannot find command '" + commandName
+ "'");
}
//默认情况下,这个值是空的
this.setActionContextClassName(controllerConfig.getProperty(
ACTION_CONTEXT_CLASS));
}
2、process方法
public void process(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// Wrap the request in the case of a multipart request
//处理"multipart/form-data",即上传文件的表单时,将request包装成MultipartRequestWrapper
request = processMultipart(request);
/*这里建立一个ActionContext,如果用户没指定actionContextClass的话,
* 默认new ServletActionContext(servletContext, request, response)
* 这个ActionContext包含了request,response,servletContext和ModuleConfig
*/
// Create and populate a Context for this request
ActionContext context = contextInstance(request, response);
// Create and execute the command.
try {
if (LOG.isDebugEnabled()) {
LOG.debug("Using processing chain for this request");
}
//执行ChainCommand,实际上这个command就是chainBase
command.execute(context);
} catch (Exception e) {
// Execute the exception processing chain??
throw new ServletException(e);
}
// Release the context.
context.release();
}