SpringMVC 源码解析

   最近在springmvc传值问题遇到麻烦,特意了解一下springmvc的源码;

首先带着几个问题:

1.springmvc是个什么东西?

2.springmvc启动的时候做了什么?

3.springmvc怎么做的请求处理?

4.controller的方法中,httpsession,httpservletrequest,httpservletrespon 为什么默认就有?

然后我就找到了一些文章  https://my.oschina.net/lichhao?tab=newest&catalogId=285356

原文介绍的比较详细,找了一些对自己有用的,摘抄下来。

1.先从springmvc 入口开始吧,我们先在web.xml里面配置了

    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:/spring/spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

从这里可以看出DispatcherServlet 这个类随着服务一起启动了。不难看出springmvc是一个原生的Servlet框架对象为依托,通过合理的抽象,制定了严谨的的处理流程。那么第一个问题有了答案。

那么,就该回想老师讲的servlet原理的。

  • Servlet 通过调用 init () 方法进行初始化。
  • Servlet 调用 service() 方法来处理客户端的请求。
  • Servlet 通过调用 destroy() 方法终止(结束)。
  • 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。

我在这贴上一段简单的servlet生命周期,如果不理解,可以去找一些servlet温故一些知识。

根据servlet的生命周期,那么我就应该从init开始

SpringMVC初始化

    springmvc初始化的时候都做了点什么呢?

    我们先找init方法进入 DispatcherServlet类,搜索init方法,没有找到,那么就他的父级

DispatcherServlet-->FrameworkServlet-->HttpServletBean

下面就一一介绍这三个类

1.HttpServletBean

主要工作:工作是一些初始化的工作,将web.xml中配置的参数设置到Servlet中。比如servlet标签的子标签init-param标签中配置的参数。

从DisPatcherServlet一直到HttpServletBean找到了init方法 下面贴一下源码

 public final void init() throws ServletException {
        if(this.logger.isDebugEnabled()) {
            this.logger.debug("Initializing servlet '" + this.getServletName() + "'");
        }

        try {
			// getServletConfig 从web.xml找到配置参数并设置到ServletConfigPropertyValues内部
            PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
			// 使用BeanWrapper 构造DisPatchServlet
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
            this.initBeanWrapper(bw);
            bw.setPropertyValues(pvs, true);  // 设置DisPatcherServlet属性
        } catch (BeansException var4) {
            if(this.logger.isErrorEnabled()) {
                this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4);
            }

            throw var4;
        }

        this.initServletBean(); // 默认不做处理,方便子类继承之后做更多的处理
        if(this.logger.isDebugEnabled()) {
            this.logger.debug("Servlet '" + this.getServletName() + "' configured successfully");
        }

    }

然后initServletBean()开始拓展

2.FrameworkServlet

主要工作:将Servlet与Spring容器上下文关联。其实也就是初始化FrameworkServlet的属性webApplicationContext,这个属性代表SpringMVC上下文,它有个父类上下文,既web.xml中配置的ContextLoaderListener监听器初始化的容器上下文。

FrameworkServlet继承了httpservletBean 并且重写了initServletBean这个方法

这个时候想:配置在Controller上的那些参数什么RequestMapping之类的

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

        long startTime = System.currentTimeMillis();

        try {
		// 初始化webApplicationContext属性
		// webApplicationContext 是继承ApplicationContext的接口
		// 该属性就是Spring容器上下文
		// FeameworkServlet的作用就是把servlet跟spring容器关联
            this.webApplicationContext = this.initWebApplicationContext();
             //为做任何处理,方便子类继承做很多的处理
	    // 不过DispatcherServlet没有重新此方法
            this.initFrameworkServlet();
        } catch (ServletException var5) {
            this.logger.error("Context initialization failed", var5);
            throw var5;
        } catch (RuntimeException var6) {
            this.logger.error("Context initialization failed", var6);
            throw var6;
        }

        if(this.logger.isInfoEnabled()) {
            long elapsedTime = System.currentTimeMillis() - startTime;
           this.logger.info("FrameworkServlet '" + this.getServletName() + "': initialization completed in " + elapsedTime + " ms");
        }

    }
 protected WebApplicationContext initWebApplicationContext() {
        WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
        WebApplicationContext wac = null;
        if(this.webApplicationContext != null) {
            wac = this.webApplicationContext;
            if(wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac;
                if(!cwac.isActive()) {
                    if(cwac.getParent() == null) {
                        cwac.setParent(rootContext);
                    }

                    this.configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }

        if(wac == null) {
            wac = this.findWebApplicationContext();
        }

        if(wac == null) {
            wac = this.createWebApplicationContext(rootContext);
        }

        if(!this.refreshEventReceived) {
            this.onRefresh(wac);
        }

        if(this.publishContext) {
            String attrName = this.getServletContextAttributeName();
            this.getServletContext().setAttribute(attrName, wac);
            if(this.logger.isDebugEnabled()) {
                this.logger.debug("Published WebApplicationContext of servlet '" + this.getServletName() + "' as ServletContext attribute with name [" + attrName + "]");
            }
        }

        return wac;
    }

this.onRefresh这个方法并没有做任何处理,方便子类继承,做更多的处理;

3.DispatcherServlet

主要工作:初始化各个功能的实现类。比如异常处理、视图处理、请求映射处理等。

DispatcherServlet重写了onRefresh这个方法

 protected void onRefresh(ApplicationContext context) {
        this.initStrategies(context);
    }

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

上面就是Spring进行处理的事了

很明显,initStrategies方法内部会初始化各个策略接口的实现类。
比如异常处理初始化initHandlerExceptionResolvers方法:SpringMVC异常处理机制详解
视图处理初始化initViewResolvers方法:SpringMVC视图机制详解

请求映射处理初始化initHandlerMappings方法:详解SpringMVC请求的时候是如何找到正确的Controller

这个时候,1,2 这两个问题,在自己心里,已经有了大概的答案。

SpringMVC对扩展开放,对修改封闭

  • 类中所有的变量声明,几乎都以接口的形式给出,并没有绑定在具体的实现类上。
  • 使用模版方法模式,在父类中对基础行为进行定义,让子类实现模版方法扩展行为。

猜你喜欢

转载自blog.csdn.net/qq_30285985/article/details/80751801