spring -mvc 总体架构

            spring -mvc 总体架构

高尚是高尚者的墓志铭,卑鄙是卑鄙者的同行证--北海   2017-03-18  10:59:01 

   前瞻:spring MVC作为当前最流行的MVC模式,其实用性及其前瞻性不言而喻,最近一直在使用springMVC,遇到问题,形成一个习惯就是先不自己考虑,直接去度娘,找不到满意的结果了,再去研究研究源码,没有进行系统的学习,这段时间正好公司活也不是很多就做个记录吧,以前一直想记录自己工作中遇见的问题,但是总是懒,觉得没有什么必要,报这样一个心态自己遇见的问题,别人早都遇见了,网上肯定有解决的办法,是一个彻底的拿来主义者,慢慢就发现这样对于自己并没有什么提高,只是一个码农,离预定目标越来越远,痛定思痛,决定重新做个记录,不求于多少访问量,只是简单的帮助别人,完善自己,如果不喜欢也不要乱喷,悄悄走开就行,有些内容是参考前辈们的,如果有什么侵权,请及时告知,谢谢!战战兢兢的,开始第一篇。官方文档:http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html

  目的:学完所有的springMVC争取自己写出来一个简单的MVC模式的实现。()

  

总体架构图:

                      (此图片来自己张开涛老师的博客,博客链接http://jinnianshilongnian.iteye.com/blog/1594806)

总体流程及模式的实现*(宏观分析):

  mvc架构的发展:对于web的模式发展可以参考http://jinnianshilongnian.iteye.com/blog/1593441

  所使用的设计模式:对于设计模式比较熟悉的朋友应该知道门面设计,也就是前段设计模式,SUN公司为Java Web开发定义了两种模型,Model 1和Model 2。Model 2是基于MVC(Model-View-Controller,模型-视图-控制)架构模式的,通常将小服务(Servlet)或过滤器(Filter)作为控制器,其作用是接受用户请求并获得模型数据然后跳转到视图;将JSP页面作为视图,用来显示用户操作的结果;模型当然是POJO(Plain Old Java Object),它是区别于EJB(Enterprise JavaBean)的普通Java对象,不实现任何其他框架的接口也不扮演其他的角色,而是负责承载数据。

流程:自己感悟:对于刚接触一个框架的时候我们先要从宏观的方面去了解这个框架的总体架构,别刚开始上来就一路dubugger,一会就不知道自己究竟在干什么了。

   ①:dispatcherServlet 是一个servlet,其继承了HttpServlet,其实他作为mvc的前段控制器,就是客户端所有的请求,委托给DispatcherServlet,有其决定本次请求有具体的那个类去处理。 

    ②:前段控制器拿到请求之后,会将请求DispatcherServlet————》HandlerMapping, HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象,返回给DispathcerServelet通过这种策略模式,很容易添加新的映射策略,(回头继续学习策略模式)。

  ③:DispatcherServlet————》HandlerAdapter :这里用到的是适配器模式,HandlerAdapter :会将所有的处理器包装成处理器适配器,(也就是对于当前的请求找到对应的方法)找到对应的处理器。

  ④:Handler将当前请求处理完成之后,返回一个ModelAndView 给前段控制器,前段控制器将view交给viewResolver处理,找到对应的视图.jsp,返回给前段控制器,前段控制器将model渲染到对应的视图上面,至此,一次完整的请求就处理完毕。

源码分析(微观分析):

  对于所有的mvc中所有的模式,器最主要的就是前段控制器:先从DispatcherServlet开始分析:从其官方的文档中看出:The DispatcherServlet is an actual Servlet (it inherits from the HttpServlet base class), and as such is declared in your web application. You need to map requests that you want the DispatcherServlet to handle, by using a URL mapping. Here is a standard Java EE Servlet configuration in a Servlet 3.0+ environmen

  DispatcherServlet是一个Servlet,继承了HttpServlet,依旧是一个web应用,对于我们开发者来说就是配置web.xml就是将请求映射到对应的处理器上,是一个标准的Servlet配置,官方给的例子:

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) {
        ServletRegistration.Dynamic registration = container.addServlet("example", new DispatcherServlet());
        registration.setLoadOnStartup(1);
        registration.addMapping("/example/*");
    }

}

大概意思就是:DispatcherServlet创建一个实例名为:example,将这个实例绑定到ServletCOntext中,在容器上下文中有效,设置加载时机,再类启动的时候加载,添加类对应的映射,跟web.xml中的配置一个意思(这些代码的运行是在Servlet3.0以上)

<web-app>
    <servlet>
        <servlet-name>example</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>example</servlet-name>
        <url-pattern>/example/*</url-pattern>
    </servlet-mapping>

</web-app>

既然DispatcherServlet是一个Servlet,其里面一个最主要的方法doService()方法是所有的servlet的执行,再看servlet方法之前,我们先大概看一下request从webServer到DispatcherServlet 的中间做了哪些工作:(搞清楚类和类之间的关系)

public class DispatcherServlet extends FrameworkServlet
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware
public interface ApplicationContextAware extends Aware

 先看最顶层的ApplicationContextAware ,这个接口void setApplicationContext(ApplicationContext applicationContext) throws BeansException;获取web容器初始化的上下文根,并注入到spring容器的上下文中,当一个类实现了这个接口(ApplicationContextAware)之后,这个类就可以方便获得ApplicationContext中的所有bean。换句话说,就是这个类可以直接获取spring配置文件中,所有有引用到的bean对象,这里我们看一下一般的web.xml的配置文件。

<!-- Spring -->
<!-- 配置Spring配置文件路径 -->

<!-- Context ConfigLocation -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/spring-context*.xml</param-value>
</context-param>

<!-- 配置Spring上下文监听器 -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring -->
<!-- Spring MVC 核心控制器 DispatcherServlet 配置 -->
<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <!-- 拦截所有的请求,交给DispatcherServlet处理,性能最好 -->
    <url-pattern>/</url-pattern>
</servlet-mapping>

ApplicationContextAware 

在web.xml中,加载顺序是listener>filter>servlet,所以spring-Context.xml先加载!加载的时候我们会设置其的扫描范围,之后加载spring-mvc的配置文件,也就是在容器初始化的时候我们会将所有扫描的bean都会放在ApplicationContext中,

HttpServletBean

  在init方法中, 首先将Servlet配置的参数使用BeanWrapper设置到DispatcherServlet中, 然后调用initServletBean子类通过这个方法进行初始化

FrameworkServlet 
入口方法是initServletBean, 里面核心方法有两句: 初始化WebApplicationContext; 初始化FrameworkServlet 
initWebApplicationContext方法里获取Spring的根容器rootContext,将webApplicationContext设置到ServletContext

DispathcerServlet

onRefresh是其入口方法, onRefresh中调用了initStrategies, 在initStrategies中调用了9个初始化方法 
首先从context(WebApplicationContext)找自定义的Bean, 找不到则getDefaultStrategy获取默认组件

请求处理流程

Servlet(属于tomcat) 
是接口规范 定义了Java如何和tomcat通信

GenericServlet

做了三件事:

  1. 实现了ServletConfig 接口,让我们可以直接调用ServletConfig中的方法
  2. 提供了无参的init方法
  3. 提供了log方法

HttpServlet(属于Java) 
将ServletRequest和ServletResponse转换为HttpServletRequest和HttpServletResponse 
实现了Servlet方法 service方法中根据方法逻辑 由doGet doPost等方法具体处理 
做了doHead doOptions doTrace的默认实现, 其中doHead调用doGet, 然后返回只有header没有body的response

HttpServletBean(属于Spring) 
对于请求的处理啥也没干

FrameworkServlet(属于Spring)

继承HttpServlet 又重写了 service doGet doPost等(除了doHead) 
service中增加了对PATCH类型请求的处理。 doGet doPut doDelete 都是自己处理, 
处理方法内统一交给(调用)processRequest方法处理, processRequest核心语句是 
doService(request, response),在DispathcerServlet中有具体实现

DispathcerServlet(属于Spring) 
在其doService方法中将webApplicationContext、localeResolver、hteme-Resolver、themeSource、FlashMap、FlashMapManager设置到request的属性中以方便调用。然后将doDispatch方法进行具体处理。 这块的详细了解:http://jinnianshilongnian.iteye.com/blog/1602617

现在所有的流程总算串起来了,不知道有什么问题不?期待各位的指点

对于doDispather()方法我们就是所有处理流程的一个重点了。

直接看源码:我们知道FrameWorkServlet里面的初始化:先初始化整个应用的上下文,之后再初始化spring-mvc所应用的bean

@Override
    protected final void initServletBean() throws ServletException {
        getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
        if (this.logger.isInfoEnabled()) {
            this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
        }
        long startTime = System.currentTimeMillis();

        try {
//初始化应用的servletContext
this.webApplicationContext = initWebApplicationContext(); initFrameworkServlet(); }

protected WebApplicationContext initWebApplicationContext() {
          WebApplicationContext rootContext =WebApplicationContextUtils.getWebApplicationContext(getServletContext());
          WebApplicationContext wac = null;

          onRefresh(wac);}

DispatcherServlet中:从onRefresh 中入手:看一下DispatcherServlet中初始化了那几个bean

  @Override
  protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
  }

 
  

  protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);
    initLocaleResolver(context);
    initThemeResolver(context);
    initHandlerMappings(context);
    initHandlerAdapters(context);
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);
    initFlashMapManager(context);
}

最主要的几个bean 处理器映射器,处理器适配器,处理器异常解析器。。。。,到此spring-mvc将所需要的所有的bean 都已经初始化完毕,也就是将所有的springMVc需要的bean加入到webApplicationContext中,供我们在整个应用中使用。
DispatcherServlet前段控制器里面的doDispatch()方法就是处理所有的流程。

try {
  ModelAndView mv = null;
  Exception dispatchException = null;

try {
  processedRequest = checkMultipart(request);
  multipartRequestParsed = (processedRequest != request);

 
  

//根据当前的请求得到器处理器执行链
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
  noHandlerFound(processedRequest, response);
  return;
}

//根据处理器找到其对应的处理器适配器

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

  String method = request.getMethod();
  boolean isGet = "GET".equals(method);
  if (isGet || "HEAD".equals(method)) {
  long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}

if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}

try {
//通过反射将请求结果所得到视图和数据放入ModelAndView  中
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}

  applyDefaultViewName(request, mv);
  mappedHandler.applyPostHandle(processedRequest, response, mv);
}
  catch (Exception ex) {
  dispatchException = ex;
}
  processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
  triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}

大体的流程就执行完毕。
  

到此基础的东西认识完毕,初次写还是很乱,下次会更好。

 

     

  

 

转载于:https://www.cnblogs.com/yefx/p/6572201.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值