Servlet和SpringMVC的初始化及请求处理过程浅析

Servlet是一套Web应用的开发规范,我们按照这套规范编码就可以实现一个Web应用,使其在Web容器中运行。
我们最开始学习J2EE时,学习和创建的就是Servlet的实现类,后来学习了MVC框架以后,尤其是SpringMVC,就很少直接创建Servlet的实现类了。虽然SpringMVC简化和隐藏了Servlet,但是我们也要了解Servlet的运行原理,这样对了解SpringMVC的原理也很有帮助

一.继承图:

继承图
首先看一下Servlet的类结构

public interface Servlet {

    public void init(ServletConfig config) throws ServletException;

    public ServletConfig getServletConfig();

    public void service(ServletRequest req, ServletResponse res)
    throws ServletException, IOException;

    public String getServletInfo();

    public void destroy();
}

Servlet是个接口,定义了init、service、destroy等方法。其中init方法在容器启动时(或Servlet第一次调用时)会被调用,进行Servlet的初始化工作;service方法会在容器接收到请求后处理请求时调用。
下面看一下Servlet接口的各个实现类,从而分析Servlet的初始化原理和Spring的DispatchServlet是如何作为请求分发器的。

二.Servlet的初始化过程—init(ServletConfig config)方法

  1. GenericServlet:

    /**重写init(ServletConfig)方法,将参数config保存在对象中,将init()方法交给实现类重写,这样既可以让本类的init(ServletConfig)得到执行,也可以让实现类的init()得到执行。这种方式在Servlet的实现类中经常用到:模板方法**/
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }
    
    public void init() throws ServletException {
    }

    重写了init方法,保存了配置参数的对象,将具体的init操作交给实现类

  2. HttpServlet: 没有重写init相关的方法,定义了一些Servlet中的常量(POST、GET等)和常用方法(doPost、doGet等),供实现类使用和重写
  3. HttpServletBean:

    @Override
    public final void init() throws ServletException {
    //注意看log的内容,是我们在启动tomcat时控制台经常看到的输出内容
    if (logger.isDebugEnabled()) {
        logger.debug("Initializing servlet '" + getServletName() + "'");
    }
    try {
        PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
        BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
        ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
        bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
        initBeanWrapper(bw);
        bw.setPropertyValues(pvs, true);
    }
    catch (BeansException ex) {
        logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
        throw ex;
    }
       /*很重要的方法,在本类中是空方法。HttpServletBean的init()方法做了基本的参数处理后,将其他的
       init操作交给了实现类,实现类不重写init()方法,而是重写initServletBean(),这样它们都会得到执行。*/
    initServletBean();
    
    if (logger.isDebugEnabled()) {
        logger.debug("Servlet '" + getServletName() + "' configured successfully");
    }
    }
  4. FrameworkServlet:

    //注意看log的内容,是我们在启动tomcat时控制台经常看到的输出内容
    @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 {
        //初始化应用上下文
        this.webApplicationContext = initWebApplicationContext();
        //交给实现类继续做初始化工作,目前未见相关实现类重写了该方法
        initFrameworkServlet();
    }。。。
    
    if (this.logger.isInfoEnabled()) {
        long elapsedTime = System.currentTimeMillis() - startTime;
        this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +elapsedTime + " ms");
    }
    }
    
    /**
    初始化应用上下文,包括子容器上下文和父容器上下文,onRefresh(ApplicationContext)方法交给实现类
    处理,DispatchServlet会在此方法中对mvc-servlet.xml文件进行读取和参数配置初始化等工作
    **/
    protected WebApplicationContext initWebApplicationContext() {
        WebApplicationContext rootContext =
                        WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;
    if (this.webApplicationContext != null) {
        // A context instance was injected at construction time -> use it
        wac = this.webApplicationContext;
        if (wac instanceof ConfigurableWebApplicationContext) {
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
            if (!cwac.isActive()) {
                if (cwac.getParent() == null) {
                    //设置子容器的父容器
                    cwac.setParent(rootContext);
                }
                //初始化应用上下文对象
                configureAndRefreshWebApplicationContext(cwac);
            }
        }
    }
       if (!this.refreshEventReceived) {
           //实现类进行操作
        onRefresh(wac);
    }
    。。。。。
    
    return wac;
    }
    
    protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
    。。。。。。。//wac的初始化工作
    //很重要的一步
    wac.refresh();
    }
    //AbstractApplicationContext的方法
    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
        prepareRefresh();
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        prepareBeanFactory(beanFactory);
        try {
             。。。。。//BeanFactory和MessageSource初始化
            onRefresh();
             。。。。。//注册监听器
        }
    }
    }
  5. DispatchServlet:

    //调用DispatchServlet的onRefresh(ApplicationContext)方法,读取mvc-servlet.xml文件,并初始化
    //HandlerMapping、HandlerAdapters等属性
     @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);
    }

三.Servlet的调用过程—service(ServletRequest req, ServletResponse res)方法

  1. GenericServlet:没有重新service(ServletRequest,ServletResponse)方法
  2. HttpServlet:

    //重写Servlet的service(ServletRequest,ServletResponse)方法,主要做了请求参数类型判断和参数转换
      @Override
    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException
    {
        HttpServletRequest  request;
        HttpServletResponse response;
    
        if (!(req instanceof HttpServletRequest &&
                res instanceof HttpServletResponse)) {
            throw new ServletException("non-HTTP request or response");
        }
    
        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;
    
        service(request, response);
    }
    //将请求分为POST、GET、DELETE等几种常见方法,然后分别进行处理。以前写Servlet时都是继承该类,然后
    //重写doGet、doPost等方法,对请求进行处理。SpringMVC的处理方式于此不同。
    protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String method = req.getMethod();
    
        if (method.equals(METHOD_GET)) {
            。。。
              doGet(req, resp);
            。。。
            }
    
        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
    
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
    
        } 
        。。。
    }
  3. HttpServletBean:未重写service或doXxx方法
  4. FrameworkServlet:

    /*重写service方法,增加了PATCH方法的处理,其他方法如GET会调用父类的FrameworkServlet重写了
    doXxx方法,实际上会调用本类的doXxx方法,也就是调用SpringMVC的统一请求处理方法---p
    rocessRequest(HttpServletRequest, HttpServletResponse)*/
      @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    
        HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
        if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
            processRequest(request, response);
        }
        else {
            super.service(request, response);
        }
    }
    @Override
    protected final void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    
        processRequest(request, response);
    }
    
    protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    
        。。。
        try {
        //具体的doService实现交给了子类
            doService(request, response);
        }
        。。
        publishRequestHandledEvent(request, response, startTime, failureCause);
        。。。
    }
  5. DispatchServlet:

    @Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        。。。//设置相关属性
        try {//该方法是SpringMVC处理请求的关键,也是DispatchServlet分发请求的关键:根据
        //pathHandlerMapping查询对应的HandlerExecutionChain,调用HandlerAdapter的handle方法进行处理,
        //获取ModelAndView对象,最后处理结果。
            doDispatch(request, response);
        }
        。。。//存储相关属性
    }
    
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值