• springMVC源码浅析


    因故,需要学习springmvc,现在demo已经跑起来。列文分析springmvc并简单对比struts2.

    springmvc的核心对象dispatcherServlet。struts2的核心对象是strutsPrepareAndExecuteFilter,拦截的方式不同,但同为前段控制器(front controller)设计模式。

    dispatcherServlet的初始化:

    JVM加载dispatcherServlet时,会先执行静态代码块:

    static{
      ClassPathResource resource = new  ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
      defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);  
    }

    这两行将springMVC包内的dispatcherServlet.properties文件中缺省的HandlerAdapter、HandlerMapping、ViewResolver等等。

    容器初始化时,会调用HttpServlet的init()方法,这个方法被httpServletBean重写了,在httpServletBean中,调用frameworkServlet的initServletBean()方法,这个方法在调用dispatcherServlet真正的onRefresh()方法,到initStrategies()。

    initStrategies()有所有的初始化工作:【老版本好像叫做initFrameworkServlet

    protected void initStrategies(ApplicationContext context) {
      initMultipartResolver(context);
      initLocaleResolver(context);
      initThemeResolver(context);
      initHandlerMappings(context);//初始化所有的请求映射,存储到dispatcherServlet的handlerMappings成员变量中(List)
      initHandlerAdapters(context);
      initHandlerExceptionResolvers(context);
      initRequestToViewNameTranslator(context);
      initViewResolvers(context);//初始化所有视图解析器,存储到dispatcherServlet的viewResolvers成员变量中(List)
      initFlashMapManager(context);
    }

    dispatcherServlet对请求的拦截:

    一个请求到达后端时,若符合我们dispatcherServlet的servletMapping,则会进入dispatcherServlet。默认会调用其父类frameworkServlet的doGet、doPost方法,这两个方法再分发到protected final void processRequest(request,response)方法中。这个方法会调用dispatcherServlet的doService(request,response)方法。

    然后在此方法中截取URI,然后把上下文等信息放在request的attribute中,调用doDispatch方法。

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
            HttpServletRequest processedRequest = request;
            HandlerExecutionChain mappedHandler = null;
            boolean multipartRequestParsed = false;
            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
            try {
                ModelAndView mv = null;
                Exception dispatchException = null;
                try {
                    processedRequest = checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    mappedHandler = getHandler(processedRequest, false);//拿到HandlerExecutionChain 
                    if (mappedHandler == null || mappedHandler.getHandler() == null) {
                        noHandlerFound(processedRequest, response);
                        return;
                    }
                    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());//拿到HandlerExecutionChain中封装的HandlerAdapter
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }
                    //执行所有的interceptor的interceptor.preHandle(request, response, this.handler)方法
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
                    try {
                        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());//执行真handlerAdapter中封装的controller真正的业务方法,返回modelAndView
                    }
                    finally {
                        if (asyncManager.isConcurrentHandlingStarted()) {
                            return;
                        }
                    }
    
                    applyDefaultViewName(request, mv);
                  //执行所有拦截器的interceptor.postHandle(request, response, this.handler, modelAndView)方法
                  mappedHandler.applyPostHandle(processedRequest, response, mv);
             }
    catch (Exception ex) { dispatchException = ex; } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); } finally { if (asyncManager.isConcurrentHandlingStarted()) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); return; } if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } //遍历所有注册的handlerMappings,拿出一个支持当前handlerMapping的adapter,封装到HandlerExecutionChain中 protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { for (HandlerMapping hm : this.handlerMappings) { HandlerExecutionChain handler = hm.getHandler(request);//不同类型的handlerMapping有不同的getHandler实现 if (handler != null) { return handler; } } return null; }

    doDispatch业务处理方法:
    1、通过URI,遍历成员变量handlerMappings,拿到URI对应的controller、interceptor放到HandlerExecutionChain中(不同类型的mapping拿的方式不一样,如SimpleUrlHandlerMapping是通过URI映射规则从map中拿到controller)。

    从doDispatcher的代码中,很明显可以看出一条线索,整个方法是围绕着如何获取HandlerExecutionChain对象,执行HandlerExecutionChain对象得到相应的视图对象,再对视图进行渲染这条主线来展开的。HandlerExecutionChain对象显得异常重要。

    因为Http请求要进入SpringMVC的处理体系,必须由HandlerMapping接口的实现类映射Http请求,得到一个封装后的HandlerExecutionChain对象。再由HandlerAdapter接口的实现类来处理这个HandlerExecutionChain对象所包装的处理对象,来得到最后渲染的视图对象。

    2、循环所有的HandlerAdapter,通过support方法拿到支持目标controller的的一个adapter。

    循环所有已注册的HandlerAdapter(处理器适配器),如果该适配器支持ha.supports(handler)当前处理器,就返回。由此可见,Spring通过HandlerAdapter使处理器解耦,实处理器(Handler)不只是仅仅局限于控制器(Controller)这一种形式。目前Spring可以支持,ServletHttpRequestHandlerThrowawayControllerController,从这一点上看Spring已为客户留出了很大空间作为扩展的口子。

    http://www.blogjava.net/hao-zhang-hi/archive/2011/03/10/346081.html

    3、调用adapter 的applyPreHandle(request,response),执行所有的interceptor的interceptor.preHandle(request, response, this.handler)方法。

    4、调用adapter的handle(request, response, mappedHandler.getHandler());去执行controller中真正的业务方法,返回ModelAndView对象。

    5、调用adapter的applyPostHandle(request,response,modelAndView)方法,执行所有拦截器的interceptor.postHandle(request, response, this.handler, modelAndView)方法。

    6、调用processDispatchResult(request,response,HandlerExecutionChain,ModelAndView,Exception),如果exception不为空,返回配置的异常modelAndView。如果exception为空,根据modelAndView中的字符串拼接视图完整路径。

    7、如我们配置了jsp的JstlView,调用view.render(Map model,request,response),调用InternalResourceView的renderMergedOutputModel方法,拿到requestDispatcher,forward到视图。最后执行mappedHandler.triggerAfterCompletion(request, response, null)

     

    Spring MVC PK Struts2

    我们用struts2时采用的传统的配置文件的方式,并没有使用传说中的0配置。spring3 mvc可以认为已经100%零配置了(除了配置spring mvc-servlet.xml外)。

    Spring MVC和Struts2的区别:

    1. 机制:spring mvc的入口是servlet,而struts2是filter(这里要指出,filter和servlet是不同的。以前认为filter是servlet的一种特殊),这样就导致了二者的机制不同,这里就牵涉到servlet和filter的区别了。

    (区别:1,servlet 流程是短的,url传来之后,就对其进行处理,之后返回或转向到某一自己指定的页面。它主要用来在
         业务处理之前进行控制.
      2,filter 流程是线性的, url传来之后,检查之后,可保持原来的流程继续向下执行,被下一个filter, servlet接收等,而servlet 处理之后,不会继续向下传递。filter功能可用来保持流程继续按照原来的方式进行下去,或者主导流程,而servlet的功能主要用来主导流程。
         filter可用来进行字符编码的过滤,检测用户是否登陆的过滤,禁止页面缓存等
    3, servlet,filter都是针对url之类的,而listener是针对对象的操作的,如session的创建,session.setAttribute的发生,在这样的事件发生时做一些事情。
         可用来进行:Spring整合Struts,为Struts的action注入属性,web应用定时任务的实现,在线人数的统计等

    4,interceptor 拦截器,类似于filter,不过在struts.xml中配置,不是在web.xml,并且不是针对URL的,而是针对action,当页面提交action时,进行过滤操作,相当于struts1.x提供的plug-in机制,可以看作,前者是struts1.x自带的filter,而interceptor 是struts2 提供的filter.
        与filter不同点:(1)不在web.xml中配置,而是在struts.xml中完成配置,与action在一起
                                ( 2  ) 可由action自己指定用哪个interceptor 来在接收之前做事)

    2. 性能:spring会稍微比struts快。spring mvc是基于方法的设计而sturts是基于类,每次发一次请求都会实例一个action,每个action都会被注入属性,而spring基于方法,粒度更细,但要小心把握像在servlet控制数据一样。spring3 mvc是方法级别的拦截,拦截到方法后根据参数上的注解,把request数据注入进去,在spring3 mvc中,一个方法对应一个request上下文。而struts2框架是类级别的拦截,每次来了请求就创建一个Action,然后调用setter getter方法把request中的数据注入;struts2实际上是通过setter getter方法与request打交道的;struts2中,一个Action对象对应一个request上下文。

    3. 参数传递:struts是在接受参数的时候,可以用属性来接受参数,这就说明参数是让多个方法共享的。

    4. 设计思想上:struts更加符合oop的编程思想, spring就比较谨慎,在servlet上扩展。

    5. intercepter的实现机制:struts有以自己的interceptor机制,spring mvc用的是独立的AOP方式。这样导致struts的配置文件量还是比spring mvc大,虽然struts的配置能继承,所以我觉得论使用上来讲,spring mvc使用更加简洁,开发效率Spring MVC确实比struts2高spring mvc是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上spring3 mvc就容易实现restful urlstruts2是类级别的拦截,一个类对应一个request上下文;实现restful url要费劲,因为struts2 action的一个方法可以对应一个url;而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了。spring3 mvc的方法之间基本上独立的,独享request response数据,请求数据通过参数获取,处理结果通过ModelMap交回给框架方法之间不共享变量,而struts2搞的就比较乱,虽然方法之间也是独立的,但其所有Action变量是共享的,这不会影响程序运行,却给我们编码,读程序时带来麻烦。

    6. 另外,spring3 mvc的验证也是一个亮点,支持JSR303,处理ajax的请求更是方便,只需一个注解@ResponseBody ,然后直接返回响应文本即可。送上一段代码: 

    @RequestMapping(value="/whitelists") public String index(ModelMap map) { Account account = accountManager.getByDigitId(SecurityContextHolder.get().getDigitId()); List<Group> groupList = groupManager.findAllGroup(account.getId()); map.put("account", account); map.put("groupList", groupList); return "/group/group-index"; }
    // @ResponseBody ajax响应,处理Ajax请求也很方便 @RequestMapping(value="/whitelist/{whiteListId}/del") @ResponseBody public String delete(@PathVariable Integer whiteListId) { whiteListManager.deleteWhiteList(whiteListId); return "success"; }

    http://www.cnblogs.com/youngdream-ppj/archive/2013/03/20/2971873.html

  • 相关阅读:
    bugKu getshell
    XCTF 进阶区 CAT
    php弱类型比较
    XCTF command_execution
    关于错误 openssl/ssl.h:没有那个文件或目录的解决办法
    libffi-dev : 依赖: libffi6 (= 3.2.1-4) 但是 3.2.1-4kord 正要被安装
    如何查看 Ubuntu下已安装包版本号
    git 下载指定tag版本的源码
    ubuntu 环境 openstack 源码包制成 deb 包
    fedora 国内源
  • 原文地址:https://www.cnblogs.com/radio/p/3283076.html
Copyright © 2020-2023  润新知