ExecAndWaitInterceptor

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;
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值