关于Template和Transaction中配置的Action执行顺序
在系统的template.xml中可以看到相关template的定义:
dummyAction
dummyAction
Placeholder
Placeholder
而且在Transaction的定义中不但指定了template,还给自己指定action:
QueryPSecretnoticeAction
stream,
这两个地方都指定了action,那么执行的时候到底是按什么规则执行了。这里可以看到模版中定义了一个名为action的Action,交易中也定义了一个名为action的Action。那么这两个action在程序执行的时候到底执行谁呢?还有一点,template中名为action的Action对应的是Placeholder,那么看名字就知道是占位符作用,这里为什么要用一个占位符呢?为什么不直接省略掉?
这些疑问都在相关Template的实现中可以找到答案,不同的template对这些Action的处理方式和顺序都不相同。
先看publicQueryTemplate它的实现类ExecutableSequenceTemplate的代码:
public class ExecutableSequenceTemplateextends AbstractSequenceTemplate{
public ExecutableSequenceTemplate() {}
protected void doInternal(Context context, Action action) throws PeException{
if ((action instanceof Executable)) {
((Executable)action).execute(context);
} else {
throw new PeException("system.executable_mismatch",
new Object[] { action.getClass().getName(), context.getTransactionId() });
}
}
}
就一个doInternal方法,对传入进来的Action进行了类型判断,并且进行了调用。看template的入口execute方法(这里在父类中):
public void execute(final Context context)throws PeException{
final Map actions;
if (getActions() == null){
Map actions = context.getTransactionConfig().getActions();
if (actions != null) {}
}else{
actions = getActions();
}
if (transactionEnabled){
getTransactionTemplate().execute(new TransactionCallback(){
public Object doInTransaction(TransactionStatus arg0)
{
try
{
for (Iterator it = actions.keySet().iterator(); it.hasNext();)
{
Action action = getAction((String)it.next(), context);
if ((action instanceof PlaceholderAction)) {
throw new PeException("system.placeholders_error",
new Object[] { getClass().getName(), context.getTransactionId() });
}
doInternal(context, action);
}
}
catch (PeException e)
{
throw new PeRuntimeException(e.getMessageKey(), e.getCause(), e.getArgs());
}
return null;
}
});
}else{
for (Iterator it = actions.keySet().iterator(); it.hasNext();){
Action action = getAction((String)it.next(), context);
if ((action instanceof PlaceholderAction)) {
throw new PeException("system.placeholders_error",
new Object[] { getClass().getName(), context.getTransactionId() });
}
doInternal(context, action);
}
}
}
上面的代码主要过程就是先判断template自己有没有配置Action,如果没有配置那么就直接获取Transaction中配置的Action。然后遍历Action的名字,将配置的action的名字传递到getAction方法中来获取对应的Action,最后将获取到的Action交给doInternal方法来执行。这里可以看到ExecutableSequenceTemplate对Action的处理方式就是直接遍历执行。
接下来看getAction方法(在父类AbstractTemplate中):
protected Action getAction(String paramString, Context paramContext) {
//优先从Transaction配置中获取对应的Action
Map localMap = paramContext.getTransactionConfig().getActions();
if (localMap == null) {
localObject = getActions().get(paramString);
return (Action)localObject;
}
Object localObject = localMap.get(paramString);
if (localObject == null) {
localObject = getActions().get(paramString);
}
return (Action)localObject;
}
这里可以看到,getAction方法会优先获取Transaction中配置的同名Action,也就是说名字相同的Action,Transaction的配置可以覆盖Template的配置(所有通过AbstractTemplate.getAction(name,context)的方式均适用)。
接着看publicTwoPhaseTrsTemplate对应的实现类TwoPhaseTrsTemplate:
public void execute(final Context context) throws PeException {
Action preAction = getAction("preAction", context);
Action aftAction = getAction("aftAction", context);
final Action action = getAction("action", context);
if ((action instanceof PlaceholderAction)) {
throw new PeException("system.placeholders_error",
new Object[] { getClass().getName(), context.getTransactionId() });
}
if (!(action instanceof Submitable)) {
throw new PeException("system.placeholders_error",
new Object[] { getClass().getName(), context.getTransactionId(), action.getClass().getName() });
}
if ((action instanceof Preparable)) {
((Preparable)action).prepare(context);
}
if (preAction != null) {
((Executable)preAction).execute(context);
}
try {
if (transactionEnabled) {
getTransactionTemplate().execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus arg0) {
try {
((Submitable)action).submit(context);
}
catch (PeException e) {
//异常处理代码
}
return null;
}
});
} else {
((Submitable)action).submit(context);
}
context.setData("_JnlStatus", "0");
}
catch (Exception e) {
//异常处理代码
} finally {
if (aftAction != null) {
((Executable)aftAction).execute(context);
}
}
}
通过代码可以看到,对于TwoPhaseTrsTemplate来说,它只会调用三个Action,而不想前面的ExecutableSequenceTemplate会遍历调用所有配置的Action,当然它同样可以在Transaction中配置Action来覆盖Template中配置的Action(因为它也是使用AbstractTemplate.getAction方法来获取Action)
by CSII@王大仙