struts2拦截器源码阅读笔记

本文解析了Struts2拦截器的工作原理,介绍了其运用AOP思想和责任链模式实现的流程,详细解读了核心调度类DefaultActionInvocation的init与invoke方法,并分析了拦截器的执行顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

拦截器,是struts最具特色的,也是被大家称赞的亮点之一,整个拦截器体系运用了AOP思想,流程由责任链模式完成。

下面将对拦截器的源码进行部分解读

struts2通过创建代理对象,由生成的代理action走过拦截器的一系列流程

StrutsPrepareAndExecuteFilter的executeAction()方法

 execute.executeAction(request, response, mapping);

略去中间调用的过程,直接进入拦截器的核心调度类DefaultActionInvocation

观察这个类,发现这个方法的参数,接受的是动态代理生成的引用

   public void init(ActionProxy proxy) {
        this.proxy = proxy;
        Map<String, Object> contextMap = createContextMap();

        // Setting this so that other classes, like object factories, can use the ActionProxy and other
        // contextual information to operate
        ActionContext actionContext = ActionContext.getContext();

        if (actionContext != null) {
            actionContext.setActionInvocation(this);
        }
        //根据代理对象,创建action的代理实例,底层是根据反射实现的
        createAction(contextMap);

        if (pushAction) {
            //把action压入栈顶
            stack.push(action);
            //将action存入上下文
            contextMap.put("action", action);
        }

        invocationContext = new ActionContext(contextMap);
        invocationContext.setName(proxy.getActionName());

        // get a new List so we don't get problems with the iterator if someone changes the list
        //获取全部的拦截器,将其存入集合之中,ArrayList,并迭代
        List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors());
        interceptors = interceptorList.iterator();
    }

invoke()方法,也是这个DefaultActionInvocation的核心类,整个拦截器的调用过程都时在这个方法中实现的。

 public String invoke() throws Exception {
        String profileKey = "invoke: ";
        try {
        //压栈
            UtilTimerStack.push(profileKey);

            if (executed) {
                throw new IllegalStateException("Action has already executed");
            }

            if (interceptors.hasNext()) {
                final InterceptorMapping interceptor = interceptors.next();
                String interceptorMsg = "interceptor: " + interceptor.getName();
                UtilTimerStack.push(interceptorMsg);
                try {
                //返回String类型的resultCode,因为最后的preResultCode和Result都是String类型
                //递归调用,执行拦截器链中的拦截器
                                resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
                            }
                finally {
                    UtilTimerStack.pop(interceptorMsg);
                }
            } else {
                resultCode = invokeActionOnly();
            }

            // this is needed because the result will be executed, then control will return to the Interceptor, which will
            // return above and flow through again
            if (!executed) {
                if (preResultListeners != null) {
                    for (Object preResultListener : preResultListeners) {
                        PreResultListener listener = (PreResultListener) preResultListener;

                        String _profileKey = "preResultListener: ";
                        try {
                            UtilTimerStack.push(_profileKey);
                            listener.beforeResult(this, resultCode);
                        }
                        finally {
                            UtilTimerStack.pop(_profileKey);
                        }
                    }
                }

                // now execute the result, if we're supposed to
                if (proxy.getExecuteResult()) {
                    executeResult();
                }

                executed = true;
            }

            return resultCode;
        }
        finally {
            UtilTimerStack.pop(profileKey);
        }
    }

在这里需要注意的是拦截执行的顺序
例:
Interceptor1
Interceptor2
action
preResultListener
Result
Interceptor2
Interceptor1
实现原理很简单,就是利用invoke的返回值调用的。

每一个拦截器都要事先Interceptor接口,接口很简单,初始化,销毁,和执行的intercepter方法,供invoke方法调用。

public interface Interceptor extends Serializable {

    void destroy();

    void init();

    String intercept(ActionInvocation invocation) throws Exception;

}

PreResultListener 的加入实现方法,PreResultListener 的执行位置在action之后,rusult之前。

   public void addPreResultListener(PreResultListener listener) {
        if (preResultListeners == null) {
            preResultListeners = new ArrayList<PreResultListener>(1);
        }

        preResultListeners.add(listener);
    }

整个拦截器因为责任链模式,充分的完成了解耦,每一个拦截器互相都不知道对方的存在,同时,这样做,提高了扩展性,当想要给拦截器栈中加一个拦截器的时候,直接插入拦截器,方便快捷。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值