您的位置:首页 > 大数据 > 人工智能

ExecAndWaitInterceptor

2010-04-20 09:13 295 查看
Struts2 的ExceAndWaitInteceptor 通过该拦截器可以实现在用户下载到指定页面之前显示一个进度信息的效果,其实现方大至是这样的:设定页面等待时间,页面采用Meta Refresh 的方式请求服务器Action,第一次请求服务器,被拦截器拦截,拦截会创建一个后台进程去拦截Action,执行Action[我们可以通过这个后台进行对拦截功能进行扩展],之后拦截会返回一个Wait的结果到客户端显示,当Refresh第二次或第n(N>2)次请求时,拦截器会根据Action的执行情况,如果Action没有执行完毕,还是返回wait结果,如果Action执行完毕,就返回Action的结果。

ExecAndWaitInteceptor中采用基于每个请求与Session绑定的方式来处理线程安全问题,拦截器可以控制Action的运行状态,因些在Action调用之前或之后做一些处理都是很容易的事情!

public static final String KEY = "__execWait";
public static final String WAIT = "wait";
protected int delay; //延迟时间
protected int delaySleepInterval = 100; // 在显示等待页面之前先等多少毫秒
protected boolean executeAfterValidationPass = false;
private int threadPriority = Thread.NORM_PRIORITY; //线程的优先级
private Container container; //容器的引用

下面是ExecAndWaitInterceptor 的拦截器方法

@SuppressWarnings("unchecked")
protected String doIntercept(ActionInvocation actionInvocation) throws Exception {
ActionProxy proxy = actionInvocation.getProxy();
String name = getBackgroundProcessName(proxy);
ActionContext context = actionInvocation.getInvocationContext();
Map session = context.getSession(); //Struts2 获取封装后的session
HttpSession httpSession = ServletActionContext.getRequest().getSession(true); //从当前请示中获取HttpSession
Boolean secondTime = true; //是否是每二次执行
if (executeAfterValidationPass) { //是否执行开关
secondTime = (Boolean) context.get(KEY); //从Action上下文获取一个键为key的值
if (secondTime == null) { //如果是第一次执行

context.put(KEY, true);
secondTime = false;
} else {
secondTime = true;
context.put(KEY, null);
}
}

//sync on the real HttpSession as the session from the context is a wrap that is created
//on every request
synchronized (httpSession) { //由于该拦截器实现是基于每个请求的,因些对每个从request相关的session进行加锁处理
BackgroundProcess bp = (BackgroundProcess) session.get(KEY + name);
if ((!executeAfterValidationPass || secondTime) && bp == null) { //bp==null--第一次被拦截
//如果当前session中获取不到对应的后台线程,将创建后台并启动后台线程
bp = getNewBackgroundProcess(name, actionInvocation, threadPriority);
session.put(KEY + name, bp); //将线程名加上前缀__execWait为Key值,将线程放入Session
//让当前线[主线程]程等待一定时间
performInitialDelay(bp); // first time let some time pass before showing wait page
secondTime = false;
}
if ((!executeAfterValidationPass || !secondTime) && bp != null && !bp.isDone()) { //isDone 在action执行完之前都为false
actionInvocation.getStack().push(bp.getAction()); //将 Action压入值栈
if (TokenHelper.getToken() != null) {
session.put(TokenHelper.getTokenName(), TokenHelper.getToken());
}

Map results = proxy.getConfig().getResults();
if (!results.containsKey(WAIT)) { //Action返回结果配置中必须包括一个wait Result
LOG.warn("ExecuteAndWait interceptor has detected that no result named 'wait' is available. " +
"Defaulting to a plain built-in wait page. It is highly recommend you " +
"provide an action-specific or global result named '" + WAIT +
"'.");
// no wait result? hmm -- let's try to do dynamically put it in for you!
//we used to add a fake "wait" result here, since the configuration is unmodifiable, that is no longer
//an option, see WW-3068
FreemarkerResult waitResult = new FreemarkerResult();
container.inject(waitResult);
waitResult.setLocation("/org/apache/struts2/interceptor/wait.ftl");
waitResult.execute(actionInvocation); //执行返回结果
return Action.NONE;
}
return WAIT;
} else if ((!executeAfterValidationPass || !secondTime) && bp != null && bp.isDone()) {
session.remove(KEY + name);
actionInvocation.getStack().push(bp.getAction());

// if an exception occured during action execution, throw it here
if (bp.getException() != null) {
throw bp.getException(); //ExecuterAndWaitInterceptor 是不处理Excepiton 的
}
return bp.getResult();
} else {
// this is the first instance of the interceptor and there is no existing action
// already run in the background, so let's just let this pass through. We assume
// the action invocation will be run in the background on the subsequent pass through
// this interceptor
return actionInvocation.invoke();
}
}
}

BackgroundProce 该后台线程类用于执行action操作

private static final long serialVersionUID = 3884464776311686443L;
protected Object action;
protected ActionInvocation invocation;
protected String result;
protected Exception exception;
protected boolean done;

/**
* Constructs a background process
*
* @param threadName The thread name
* @param invocation The action invocation
* @param threadPriority The thread priority
*/
public BackgroundProcess(String threadName, final ActionInvocation invocation, int threadPriority) {
this.invocation = invocation;
this.action = invocation.getAction();
try {
final Thread t = new Thread(new Runnable() {
public void run() {
try {
beforeInvocation(); //在调用Action之前可以做一些处理
result = invocation.invokeActionOnly();
afterInvocation(); //在调用Action之处处理一些事情
} catch (Exception e) {
exception = e;
}
done = true;
}
});
t.setName(threadName);
t.setPriority(threadPriority);
t.start(); //启动线程
} catch (Exception e) {
exception = e;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: