zoukankan      html  css  js  c++  java
  • Spring MVC框架的设计理念

    要使用Spring MVC,只需要在web.xml中配置一个DispatcherServlet(前端控制器),再定义一个dispatcherServlet-servlet.xml(Spring MVC 默认配置文件名)的配置文件,一个基于Spring MVC的应用就创建好了。使用Spring MVC也比较简单,我们只需要扩展一个路径映射关系(@requestMapping映射);定义一个视图解析器(定义一个Handler);再定义一个业务逻辑的处理流程(Handler中的处理方法),Spring MVC 就能够帮你完成所有的MVC功能

    Spring MVC总体设计

    DispatcherServlet类继承了HttpServlet,在Servlet的init方法调用时DispatcherServlet执行Spring MVC的初始化工作。DispatcherServlet进行初始化是在initStrategies方法中定义的8件事

    • initMultipartResolver:初始化MultipartResolver,用于文件上传。如果有文件上传,会自动将HttpServletRequest包装成DefaultMultipartHttpServletRequest,并且将每个上传的内容封装成CommonsMultipartFile对象
    • initLocaleResolver:用于处理应用的国际化问题。通过解析请求的Local和设置响应的Local来控制应用中的字符编码问题
    • initThemeResolver:用于定义一个主题,例如可以根据用户的喜好来设置用户访问页面的样式,可以将这个样式作为Theme Name保存,保存在请求的COokie或者服务端的Session中,以后每次请求根据这个Theme Name返回特定的内容
    • initHandlerMappings:用于定义用户设置的请求映射关系,将用户请求的URL映射成以一个个Handler实例。如果没有定义,将获取DispatcherServlet.properties文件默认的两个HandlerMapping,分别是BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping
    • initHandlerAdapters:用于根据Handler的类型定义不同的处理规则,Spring MVC会根据设定的Adapter去调用Handler实例。同样HandlerAdapters也必须定义,如果没有定义,将获取DispatherServlet.properties文件中默认的4个HandlerAdapter,分别是HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter,ThrowawayControllerHandlerAdapter和AnnotationMethodHandlerAdapter
    • initHandlerExceptionResolvers:当Handler处理错误时,会通过这个Handler来统一处理,默认的实现类是SimpleMappingExceptionResolver,将错误日志记录在log文件中,并且转到默认的错误页面
    • initRequestToViewNameTranslator:将指定的ViewName按照定义的RequestToViewNameTranslator替换成想要的格式,例如加上前缀或后缀
    • initViewResolvers:用于将View解析成页面,在ViewResolvers中可以设置多个解析策略,如可一个根据JSP来解析,或者FreeMarket,Velocity等等。默认的解析策略是InternalResourceViewResolver,按照JSP页面来解析

    从上述初始化策略可以看出,在一个请求中可能需要我们扩展的地方都定义了扩展点,只需要实现相对应的接口类,并创建一个Spring Bean就能扩展Spring MVC框架了

    在Spring MVC框架中,有3件事事用户必须定义和扩展的:定义URL映射规则,实现业务逻辑代码的Handler对象,渲染模板资源。而连接实现业务逻辑代码的Handler对象和渲染模板资源的纽带就是Model模型

    DispatcherServlet启动过程中做了哪些事情

    HttpServlet初始化调用了HttpServletBean的init方法,该方法的作用是获取Servlet中的init参数,并创建一个BeanWrapper对象,然后让子类真正执行BeanWrapper的初始化工作。但是HttpServletBean的子类FrameworkServlet和DispatherServlet都没有覆盖initBeanWrapper(bw)方法,所以创建的BeanWrapper对象没有任何作用,Spring MVC容器也不是通过BeanWrapper来创的

    Spring MVC的容器创建是在FrameworkServlet的initServletBean()方法中完成的,这个方法会创建WebApplicationContext对象,并调用其refresh()方法来完成配置文件的加载,配置文件的加载同样是先查找Servlet的init-param参数中设定的路径,如果没有,会根据dispatcherServlet-servlet.xml名称来查找XML文件。Spring MVC容器在加载过程时会调用DispatcherServlet的initStrategies方法完成初始化工作,也就是上述8个组件的初始化,8个组件对应8个Bean都保存在DispatcherServlet类中

    Control设计

    Spring MVC的Control主要由HandlerMapping和HandlerAdapters两个组件提供。HandlerMapping负责映射用户的URL和对应的处理类,HandlerMapping没有规定这个URL与应用的处理类如何映射,在HandlerMapping接口中只是定义了根据URL必须返回一个由HandlerExecutionChain代表1的处理链,我们可以在这个处理链中添加任意的HandlerAdapter实例来处理这个URL对应的请求,这个设计思路和在Servlet规范中的Filter处理是类似的

    HandlerMapping初始化

    Spring MVC本身也提供了很多HandlerMapping的实现,默认使用的是BeanNameUrlHandlerMapping,可以根据Bean的name属性映射到URL中

    以上使用BeanNameUrlHandlerMapping需要在Spring MVC配置文件中配置Bean的方式,来映射name与其对应的class处理类,而现在更多使用@RequestMapping注解来使用Spring MVC

    HanlerMapping的作用就是帮助我们管理URL和处理类的映射关系,简单来说就是,将一个或者多个URL映射到一个或者多个Spring Bean中

    Spring MVC提供了一个HandlerMapping的抽象类AbstractHandlerMapping,AbstractHandlerMapping同时还实现了Ordered接口并继承了WebApplicationObjectSupport类,可以让HandlerMapping通过设置setOrder方法提高优先级,并通过覆盖initApplicationContext方法实现初始化的一些工作

    HandlerMapping的初始化工作完成的两个最重要的工作就是将URL与Handler的对应关系保存在handlerMap集合中,并将所有的interceptors(拦截器)对象保存adaptedInterceptors数组中,等请求到来时执行所有的adaptedInterceptors数组中的interceptor对象。所有的interceptor对象必须实现HandlerInterceptor接口

    如果用户没有自定义HandlerMapping的实现类,Spring MVC默认提供了2个实现类(BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping)

    HandlerAdapter初始化

    Spring MVC首先要帮助我们把URL对应到一个Handler,那么这个Handler必定符合某种规则,最常见可以想到的就是我们所有的Handler都实现某个接口,然后就调用这个接口中定义的特殊方法(Struct的实现),但是Spring MVC采用另一种方式,也就是HandlerAdapter,我们的URL对应的Handler可以实现任何接口,每个接口可以定义不同的方法完全没有问题。Spring MVC的HandlerAdapter机制可以让Handler的实现更加灵活,不需要和其他MVC框架一样与某个接口绑定起来,不同的Handler甚至可以指定不同的Adapter去处理

    HandlerAdapter初始化就是创建一个HandlerAdapter对象,将这个对象保存在DispatcherServlet的handlerAdapters集合中。当Spring MVC将某个URL对应到某个Handler时,在handlerAdapters集合中查询哪个handlerAdapter对象兼容这个Handler,这个handlerAdapter对象将被返回,并调用这个handlerAdapter接口对应的方法

    如果用户没有自定义HandlerAdapter的实现类,Spring MVC默认提供了4个实现类(HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter,ThrowawayControllerHandlerAdapter和AnnotationMethodHandlerAdapter)

    Control的逻辑调用

    整个Spring MVC的调用是从DispatcherServlet的doService方法开始的,在doService方法中会将ApplicationContext,localeResolver,themeResolver等对象添加到request中以便后面使用。接着调用doDispatch方法,这个方法主要是处理用户请求

    Control的处理逻辑关键就是在DispatcherServlet类的handlerMappings集合中根据请求的URL匹配每个HandlerMapping对象中的某个Hanlder,匹配成功之后就会返回整个Handler的处理链HandlerExecutionChain对象,而在这个HandlerExecutionChain对象中将会包含用户自定义的多个HandlerInterceptor对象。在HandlerInterceptor接口中定义的3个方法preHandle,postHandle和afterCompletion,其中preHandle和postHandle分别在Handler执行前和执行后执行;afterCompletion在View渲染完成,DispatcherServlet返回之前执行,这里值得注意的是,当preHandle返回false时false时,当前的请求就在执行完afterCompletion后直接返回,Handler将不再执行

    Handler的类型是由HandlerAdapter决定的,DispatcherServlet会根据Handler对象在其handlerAdapters集合中匹配哪个HandlerAdapter实例来支持该Handler对象,接下来执行Handler对象的相应方法,如该Handler对象的相应方法返回一个ModelAndView对象,就需要去执行View渲染

    Model设计

    ModelAndView对象是连接业务逻辑层与View展现层的桥梁,对Spring MVC 来说它也是连接Handler与View的桥梁。ModelAndView对象顾名思义会持有一个ModelMap对象和一个View对象或者View名称。ModelMap对象就是执行模板渲染时所需要的变量对应的实例,如JSP通过request.getAttribute(String)获取的JSTL标签名对应的对象,以及在Velocity中context.get(String)获取的$foo对应的变量实例

    ModelMap其实也是一个Map,在Handler中将模板所需要的数据保存在这个Map中,然后传递到View对应的ViewResolvers中,不同的ViewResolvers会对这个Map中的数据进行不同的处理方式,如Velocity中将这个Map保存到org.apache.velocity.VelocityContext中,而对于freemarker模板来说就是将ModelMap包装成freemarker.template.TemplateHashModel,对于JSP来说就将每个ModelMap中的元素分别设置到request.setAttribute(modelName, modelValue)中

    View设计

    对于Spring MVC的View模块来说,它由两个组件支持,分别是RequestToViewNameTranslator和ViewResolver。RequestToViewNameTranslator支持用户定义对ViewName的解析,如将请求的ViewName加上前缀或者后缀,或者替换成特定的字符串等。而ViewResolver用于根据用户请求的ViewName创建合适的模板引擎来渲染最终的页面,ViewResolver会根据ViewName创建一个View对象,调用View对象的void render(Map model, HttpServletRequest request, HttpServletResponse response)方法渲染页面

    viewNameTranslator的初始化工作比较简单,只是让Spring MVC创建的Bean对象保存在DispatcherServlet的viewNameTranslator属性中。而ViewResolver的初始化过程如下:

    ViewResolver接口有个抽象的实现类AbstractCachingViewResolver,这个类定义了一个抽象方法View loadView(String viewName, Locale local),该方法根据viewName创建View对象。UrlBasedViewResolver类实现了AbstractCachingViewResolver抽象类,通过设置ViewClass来创建View对象。如果使用的是FreeMarkerViewResolver类,则会将ViewClass设置为FreeMarkerView.class;如果使用VelocityViewResolver类,则会将ViewClass设置为VelocityView.class;如果使用InternalResourceViewResolver类,则会将ViewClass设置为InternalResourceView.class

    由于AbstractCachingViewResolver抽象类也继承了WebApplicationObjectSupport,所以所有的AbstractCachingViewResolver子类可以通过覆盖initApplicationContext方法在Spring MVC框架启动时完成初始化工作

    JSP对应的ViewResolver是InternalResourceViewResolver类,当调用resolveViewName方法时会调用createView方法,将ViewName属性对应的InternalResourceView类实例化。最后调用InternalResourceView的render方法渲染JSP页面

  • 相关阅读:
    C++ 将对象写入文件 并读取
    IronPython fail to add reference to WebDriver.dll
    How to Capture and Decrypt Lync Server 2010 TLS Traffic Using Microsoft Tools
    .net code injection
    数学系学生应该知道的十个学术网站
    Difference Between Currency Swap and FX Swap
    Swift开源parser
    谈谈我对证券公司一些部门的理解(前、中、后台)[z]
    JDK8记FullGC时候Metaspace内存不会被垃圾回收
    JVM源码分析之JDK8下的僵尸(无法回收)类加载器[z]
  • 原文地址:https://www.cnblogs.com/lz2017/p/14456528.html
Copyright © 2011-2022 走看看