ComposableRequestProcessor的process方法中,最核心的部分实际上是chainBase这个对象来处理的。
在ActionServlet.init执行完之后,这个chainBase对象中包含三个command。当chainBase.excute()时,会分别执行三个command的excute。而这三个command中,又由于有lookUpCommand的存在,导致命令链的跳转,最终执行了个不止3个command。实际上,按照chain-config.xml,这个chainBase会执行process-action,process-view。
先看ChainBase代码
package org.apache.commons.chain.impl;
public class ChainBase implements Chain {
public ChainBase() {
}
public ChainBase(Command command) {
addCommand(command);
}
public ChainBase(Command[] commands) {
if (commands == null) {
throw new IllegalArgumentException();
}
for (int i = 0; i < commands.length; i++) {
addCommand(commands[i]);
}
}
public ChainBase(Collection commands) {
if (commands == null) {
throw new IllegalArgumentException();
}
Iterator elements = commands.iterator();
while (elements.hasNext()) {
addCommand((Command) elements.next());
}
}
<span style="white-space:pre"> </span>//存放命令链
protected Command[] commands = new Command[0];
protected boolean frozen = false;
<span style="white-space:pre"> </span>//添加command到命令链
public void addCommand(Command command) {
if (command == null) {
throw new IllegalArgumentException();
}
if (frozen) {
throw new IllegalStateException();
}
Command[] results = new Command[commands.length + 1];
System.arraycopy(commands, 0, results, 0, commands.length);
results[commands.length] = command;
commands = results;
}
public boolean execute(Context context) throws Exception {
// Verify our parameters
if (context == null) {
throw new IllegalArgumentException();
}
// Freeze the configuration of the command list
frozen = true;
// Execute the commands in this list until one returns true
// or throws an exception
boolean saveResult = false;
Exception saveException = null;
int i = 0;
int n = commands.length;
for (i = 0; i < n; i++) {
try {
<span style="white-space:pre"> </span>//从第一个command开始执行excute,如果返回值是true,则break,否则继续执行
saveResult = commands[i].execute(context);
if (saveResult) {
break;
}
} catch (Exception e) {
<span style="white-space:pre"> </span>//拿到command.excute产生的异常
saveException = e;
break;
}
}
// 保证commands[0]到commands[i]都已经执行过excute方法
if (i >= n) { // Fell off the end of the chain
i--;
}
boolean handled = false;
boolean result = false;
for (int j = i; j >= 0; j--) {
<span style="white-space:pre"> </span>//org.apache.commons.chain.Filter(继承自Command)
if (commands[j] instanceof Filter) {
try {
<span style="white-space:pre"> </span>//后处理
result =
((Filter) commands[j]).postprocess(context,
saveException);
if (result) {
handled = true;
}
} catch (Exception e) {
// Silently ignore
}
}
}
// Return the exception or result state from the last execute()
if ((saveException != null) && !handled) {
throw saveException;
} else {
return (saveResult);
}
}
Command[] getCommands() {
return (commands);
}
}
LookUpCommand的代码
package org.apache.commons.chain.generic;
import org.apache.commons.chain.Catalog;
import org.apache.commons.chain.CatalogFactory;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.apache.commons.chain.Filter;
public class LookupCommand implements Filter {
// -------------------------------------------------------------- Constructors
public LookupCommand() {
this(CatalogFactory.getInstance());
}
public LookupCommand(CatalogFactory factory) {
this.catalogFactory = factory;
}
// -------------------------------------------------------------- Properties
private CatalogFactory catalogFactory = null;
public void setCatalogFactory(CatalogFactory catalogFactory) {
this.catalogFactory = catalogFactory;
}
public CatalogFactory getCatalogFactory() {
return this.catalogFactory;
}
private String catalogName = null;
public String getCatalogName() {
return (this.catalogName);
}
public void setCatalogName(String catalogName) {
this.catalogName = catalogName;
}
private String name = null;
public String getName() {
return (this.name);
}
public void setName(String name) {
this.name = name;
}
private String nameKey = null;
public String getNameKey() {
return (this.nameKey);
}
public void setNameKey(String nameKey) {
this.nameKey = nameKey;
}
private boolean optional = false;
public boolean isOptional() {
return (this.optional);
}
public void setOptional(boolean optional) {
this.optional = optional;
}
private boolean ignoreExecuteResult = false;
public boolean isIgnoreExecuteResult() {
return ignoreExecuteResult;
}
public void setIgnoreExecuteResult(boolean ignoreReturn) {
this.ignoreExecuteResult = ignoreReturn;
}
private boolean ignorePostprocessResult = false;
public boolean isIgnorePostprocessResult() {
return ignorePostprocessResult;
}
public void setIgnorePostprocessResult(boolean ignorePostprocessResult) {
this.ignorePostprocessResult = ignorePostprocessResult;
}
// ---------------------------------------------------------- Filter Methods
public boolean execute(Context context) throws Exception {
<span style="white-space:pre"> </span>//getCommand
Command command = getCommand(context);
if (command != null) {
<span style="white-space:pre"> </span>//执行command的excute
boolean result = (command.execute(context));
<span style="white-space:pre"> </span>//表示是否忽略command的执行结果
if (isIgnoreExecuteResult()) {
return false;
}
return result;
} else {
return (false);
}
}
public boolean postprocess(Context context, Exception exception) {
Command command = getCommand(context);
if (command != null) {
if (command instanceof Filter) {
boolean result = (((Filter) command).postprocess(context, exception));
if (isIgnorePostprocessResult()) {
return false;
}
return result;
}
}
return (false);
}
// --------------------------------------------------------- Private Methods
protected Catalog getCatalog(Context context) {
CatalogFactory lookupFactory = this.catalogFactory;
if (lookupFactory == null) {
lookupFactory = CatalogFactory.getInstance();
}
String catalogName = getCatalogName();
Catalog catalog = null;
if (catalogName == null) {
// use default catalog
catalog = lookupFactory.getCatalog();
} else {
catalog = lookupFactory.getCatalog(catalogName);
}
if (catalog == null) {
if (catalogName == null) {
throw new IllegalArgumentException
("Cannot find default catalog");
} else {
throw new IllegalArgumentException
("Cannot find catalog '" + catalogName + "'");
}
}
return catalog;
}
protected Command getCommand(Context context) {
<span style="white-space:pre"> </span>//获取到catalog
Catalog catalog = getCatalog(context);
Command command = null;
<span style="white-space:pre"> </span>//获取到commandname,实际上就是lookupcommand标签的name属性
String name = getCommandName(context);
if (name != null) {
<span style="white-space:pre"> </span>//根据name找到command
<span style="white-space:pre"> </span>//这里其实是不会找到lookupcommand的,因为catalog在添加command的键值对(name做key,command对象做value)时,只有上一层标签时catalog时才会有;如果上级标签不是catalog,则只可能执行chain.addCommand(command),这种情况下,是没有name做key的
command = catalog.getCommand(name);
if ((command == null) && !isOptional()) {
if (catalogName == null) {
throw new IllegalArgumentException
("Cannot find command '" + name
+ "' in default catalog");
} else {
throw new IllegalArgumentException
("Cannot find command '" + name
+ "' in catalog '" + catalogName + "'");
}
}
return (command);
} else {
throw new IllegalArgumentException("No command name");
}
}
protected String getCommandName(Context context) {
String name = getName();
if (name == null) {
name = (String) context.get(getNameKey());
}
return name;
}
}
从代码可以看出,lookupcommand实际上就是用来跳转命令链的。这样的好处就是使命令链清晰,不必重复配置。