• Struts2 拦截器配置以及实现


    @(Java ThirdParty)[Struts|Interceptor]

    Struts2 拦截器配置以及实现

    Struts2的拦截器应用于Action,可以在执行Action的方法之前,之后或者两者。用于处理一些公共的方法,而不影响原有的代码,并且使得可以关注功能的实现,分离关注点。比如防止重复提交等。
    如下图(图片来自Struts2文档Interceptor章节):

    拦截器配置

    注:以下配置均来自于Struts2官方的例子
    Struts2内置了一些拦截器,也可以通过实现Interceptor接口来自定义拦截器。


    如下,在struts.xml中配置自定义拦截器以及引用定义的拦截器:

    <package name="default" extends="struts-default">
       <interceptors>
           <interceptor name="timer" class=".."/>
       </interceptors>
     
       <action name="login"
          class="tutorial.Login">
            <interceptor-ref name="timer"/>
             <result name="input">login.jsp</result>
       </action>
    </package>
    

    如果定义多个拦截器,像上面那样一个个引用显然是很费劲的,这里可以将多个打包为一个拦截器栈,直接引用该拦截器栈即可:

    <package name="default" extends="struts-default">
       <interceptors>
            <interceptor name="timer" class=".."/>
            <interceptor name="logger" class=".."/>
            <interceptor-stack name="myStack">
               <interceptor-ref name="timer"/>
               <interceptor-ref name="logger"/>
            </interceptor-stack>
        </interceptors>
     
    	<action name="login"
    	     class="tutuorial.Login">
    	         <interceptor-ref name="myStack"/>
    	         <result name="input">login.jsp</result>
    	</action>
    </package>
    

    Struts2 拦截器实现

    在先介绍Struts2拦截器实现时,需要先介绍一个设计模式,拦截过滤器,Struts2采用了该设计模式来实现,文档中注解了说明是使用Command设计模式,但是我觉得用Intercepting filter来理解比较好理解。

    Intercepting filter pattern

    在wiki中Intercepting Filter定义为:JavaEE设计模式,用于创建可插拔式过滤器,用于处理通用的服务,而不需要改变和兴请求的处理代码。这涉及了四个组件:Filter Manager,Filter chain,Filters,Target。如下:
    在下图,可以看成FilterManager维护着一系列的Filter,并且知道Target,这里可以实现为:FilterManager内部维护一个List<Filter>,该List作为Filter Chain。
    注:图片来自Wiki

    处理流程如下:
    注:图片来自Wiki

    Struts2 拦截器实现

    Struts2中DefaultActionInvocation可以看做一个FilterManager,其中有Iterator<InterceptorMapping>,可以看做FilterChain,即包含了所有需要拦截该Action的Interceptor,其中Object action为真正的Target。如下图:

    Interceptor接口:

    public interface Interceptor extends Serializable {
        void destroy();
        void init();
        String intercept(ActionInvocation invocation) throws Exception;
    }
    

    主要执行流程在DefaultActionInvocation.invoke方法中,该方法用递归来实现链式调用(和Tomcat中实现FIlter一样):

    public String invoke() throws Exception {
    		// 省略了部分代码...
    
    		// 如果还有Interceptor,则继续(递归条件)
            if (interceptors.hasNext()) {
                try {
                    // 获取拦截器,并将当前对象传递给拦截器,由拦截器决定是要需要继续执行,例如:invocation.invoke(),如果执行了,则继续递归,直到执行完所有的拦截器,如果没有调用该方法,即拦截了,则这里就终止递归了。
                    resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
                }
                finally {
                    UtilTimerStack.pop(interceptorMsg);
                }
            } else {
                // 只有执行完所有拦截器,才执行Action的方法
                resultCode = invokeActionOnly();
            }
    	
    }
    

    Tomcat Filter实现

    Tomcat中Filter的实现和上面差不多,不过其中的类名和概念的名称比较匹配。如下:

    ApplicationDispatcher通过使用FilterChain来实现Filter链式调用。
    其中ApplicationFIlterChain.internalDoFilter为核心的代码:

    private void internalDoFilter(ServletRequest request, 
                                  ServletResponse response)
        throws IOException, ServletException {
    
        // 通过pos来记录当前执行的Filter,只有到所有Filter执行完(递归终止条件之一)
        if (pos < n) {
            ApplicationFilterConfig filterConfig = filters[pos++];
            Filter filter = null;
            try {
                filter = filterConfig.getFilter();
    
                if (request.isAsyncSupported() && "false".equalsIgnoreCase(
                        filterConfig.getFilterDef().getAsyncSupported())) {
    			// ...
                    
                } else {  
                    // Filter.doFilter,通过传入当前对象,来实现递归调用,将控制权传递给Filter,由Filter来决定是否需要继续执行下去
                    filter.doFilter(request, response, this);
                }
    
            return;
        }
        
        try {
    
            if ((request instanceof HttpServletRequest) &&
                (response instanceof HttpServletResponse)) {
                    
                if( Globals.IS_SECURITY_ENABLED ) {
    				// ... 
                } else {  
    	            // 执行Target真正的方法
                    servlet.service(request, response);
                }
            } else {
                servlet.service(request, response);
            }
       }
       // ...
    }
    

    参考文档:

    Wiki:
    https://en.wikipedia.org/wiki/Intercepting_filter_pattern
    https://en.wikipedia.org/wiki/Interceptor_pattern
    官方文档:
    http://struts.apache.org/docs/interceptors.html

  • 相关阅读:
    sql语句常考知识点总结
    服务器搭建
    软件测试面试题
    linux常用命令
    kibana常用查询删除语法
    python从kafka消费数据
    foxmail客户端,写邮件窗口弹不出来
    JMeter学习——测试文件下载
    python中取两个列表中不同的元素
    MySQL主从复制
  • 原文地址:https://www.cnblogs.com/jabnih/p/5720914.html
Copyright © 2020-2023  润新知