• Struts学习笔记(启动过程)


         最近学习了一下Struts2,之前用过1,大致了解这个框架是什么东西,但是很少用到,现在有时间,正好学学它。Struts 2以WebWork为核心,采用拦截器的机制来处理用户的请求,这一点跟1完全不一样,而且以职责链模式设计的拦截器可谓Struts2的基石,异常处理,国际化等等处理都在拦截器的实现中完成了。

         Struts2支持多种表达式语言(OGNL,JSTL,Groovy还有Velocity,第一种是默认),印象中1中取值让人很头大,jsp中的代码也是乱的不行,到了2的时候,OGNL相当方便,一句<s:property value="xx" />就足矣了,然后再弄明白#、%和$这仨符号在什么情况下用,表达式这块就ok了,剩下不会的用到的时候看官方文档。

         专注看了下拦截器的过程,一个请求首先经由应用服务器(本人用的是resin)的分配,根据web.xml中配置filter发到StrutsPrepareAndExecuteFilter.doFilter()中,然后方法中设置编码和国际化,创建上下文,分配派发线程,准备Action映射等一系列初始化操作之后,来到了要执行下一步的地方。

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;
    
            try {
                prepare.setEncodingAndLocale(request, response);
                prepare.createActionContext(request, response);
                prepare.assignDispatcherToThread();
                if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
                    chain.doFilter(request, response);
                } else {
                    request = prepare.wrapRequest(request);
                    ActionMapping mapping = prepare.findActionMapping(request, response, true);
                    if (mapping == null) {
                        boolean handled = execute.executeStaticResourceRequest(request, response);
                        if (!handled) {
                            chain.doFilter(request, response);
                        }
                    } else {
                        execute.executeAction(request, response, mapping); // 这里将要执行下一步过程
                    }
                }
            } finally {
                prepare.cleanupRequest(request);
            }
        }

    接下来在Dispatcher.serviceAction()中,会调用StrutsActionProxy.execute(),在这里面会调用DefaultActionInvocation.invoke(),此时就该拦截器出场了。

        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 = (InterceptorMapping) interceptors.next();
                    String interceptorMsg = "interceptor: " + interceptor.getName();
                    UtilTimerStack.push(interceptorMsg);
                    try {
                        // interceptors是一个有序的拦截器列表,如果没有遍历完这个列表,程序将不会往下走,而是继续调用下一个拦截器的处理过程
                        // 在拦截器的intercept()方法中,会回调invocation.invoke()回到这个方法开始的时候,继续寻找下一个拦截器
                        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);
            }
        }

    就像Struts2文档中的图一样,一层层的拦截器包围着待调用的action,等action返回之后,再一层层突破,实现双向拦截。

    overview

    在debug过程中打上断点,可以清楚地看到整个过程

    image

    这就是一个请求被拦截器层层过滤的大致过程,同样也是一个典型的职责链模式的精巧实现

  • 相关阅读:
    array and ram
    char as int
    pointer of 2d array and address
    Install SAP HANA EXPRESS on Google Cloud Platform
    Ubuntu remount hard drive
    Compile OpenSSL with Visual Studio 2019
    Install Jupyter notebook and tensorflow on Ubuntu 18.04
    Build OpenCV text(OCR) module on windows with Visual Studio 2019
    Reinstall VirtualBox 6.0 on Ubuntu 18.04
    Pitfall in std::vector<cv::Mat>
  • 原文地址:https://www.cnblogs.com/Cratical/p/2677433.html
Copyright © 2020-2023  润新知