SpringMVC容器的DispatchServlet初始化(未完。。)

这篇博客详细分析了SpringMVC中的DispatchServlet初始化过程,从Object到GenericServlet,再到HttpServlet和HttpServletBean,最后聚焦于FrameworkServlet及其如何与Spring框架结合。特别提到了DispatchServlet的onRefresh方法,探讨了其在Spring上下文刷新时的作用。
摘要由CSDN通过智能技术生成

DispatchServlet初始化过程分析:

  1. 类的立体结构
    整体继承类结构:
    DispatctServlet体系结构
    我个人理解的各个类及其作用:
    Object类类结构
    Object所有类最终的父类,实现细节用javap -c指令得,java7是编译时发现没有父类编译器会直接后面添加extends Object,java8后测试发现并没有显式的添加,细节应该由JVM实现。回过头来看,继承Object类能得到底层这些native方法getClass();hashCode();notify();wait()对于DispatchServlet以及其他所有类来说,在反射、集合、多线程这几块用的比较多。
    这里写图片描述
    GenericServlet一个抽象类,抽象类更多的是一种描述,具体实现交给子类。对比servlet接口,他为子类多作的事情:基本的属性Servletconfig及初始参数获取方法,servise方法依然是无协议的ServletRequest形式(例如没有加http),增加无参数的init方法方便子类覆盖,增加一些log记录方法。(直接继承servlet初始基本流程:web容器(tomcat)通过web.xml配置或者注解获取ServletConfig对象参数,将ServletConfig传入init(servletconfig sc)方法得到一个servlet。
    子类继承GenericServlet需要重写Service方法)
    这里写图片描述
    HttpServlet:重写service(ServletRequest,ServeltResponse)方法,仅仅只是将两个参数强转类型为HttpServletRequest/HttpServletResponse再调用自身的带Http的service方法;这个方法做的事:根据请求方法GET调用doget,POST调用doPost等。(其中doGet需要判断,lastModify=-1直接调用,请求信息中时间小于lastModify时间就更新,并把lastModify更新至响应,在调用doget,如果不小于,直接返回304浏览器直接取缓存)。doGet\doPost方法供子类重写,而不需要重写doService方法。doTrace主要将一些请求头信息写入响应(测试用?),doOption()主要借助getAllDeclareMethod(Class)方法响应头写入子类所有重写方法的信息(Allow属性)。
    子类继承HttpServlet方法需要重写doXxx方法和自己需要init()方法,否则实例处理请求时将抛出异常。(后面的frameworkservlet重写了doXxx系列方法)
    这里写图片描述
    抽象类HttpServletBean 重写了init()方法,这个方法能将web.xml中init-param参数注入进该Servlet中。该方法主要源码:
//ServletConfigPropertyValues这个类是HttpservletBean的内部类(便于我自己理解,类比为<String,Object>linkedHashMap)追踪构造源码,取出config的initparams遍历,存储进ProperValues,另外在requiredProperties移除,最终检测扔有就抛出缺少必要属性异常。
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(),this.requiredProperties);
//把当前servlet对象进行包装
BeanWrapper bw =PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment));
//默认实现是空的
initBeanWrapper(bw);
//将属性设置入当前包装对象。意味着web.xml配置的属性init-param,此时已经设置入对象了。如果新建一个Servlet继承HttpServletBean,我的servlet也能直接用init-param设置属性(需要提供public 修饰的setXxx方法),单纯继承HttpServlet是不行的。
(过程其实远远没有看上去这么几行代码简单,再细细讨论已经是Spring的底层了。太多)
bw.setPropertyValues(pvs, true);

继承HttpServletBean按照需要可重写方法:initServletBean 设置bean属性值
这里写图片描述
FrameworkServlet :框架相关的Servlet,重写了inservletbean();该方法源代码:

try {
//初始容器
            this.webApplicationContext = initWebApplicationContext();
//该默认空交给子类实现
            initFrameworkServlet();
        }

继续追踪initWebApplicationContext();

    protected WebApplicationContext initWebApplicationContext() {
//这句代码可以简单看成=servletContext.getAttr(webappName + ".ROOT")
    WebApplicationContext rootContext =
 WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;

        if (this.webApplicationContext != null) {
            //发现已经有了web上下文,直接拿来用
            wac = this.webApplicationContext;
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
                if (!cwac.isActive()) {
                //如果上下文不是当前活动的
                    if (cwac.getParent() == null) {
//父类没有注入,将Spring 的rootContext注入为父类
                        cwac.setParent(rootContext);
                    }
                    //并刷新Spring上下文
                    configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
        if (wac == null) {
            //简化看成:servletContext.getattr(contextAttribute);
            wac = findWebApplicationContext();
        }
        if (wac == null) {
            //没找到,设置XmlWebApplicationContext为当前上下文设置父上下文并刷新
            wac = createWebApplicationContext(rootContext);
        }

        if (!this.refreshEventReceived) {
        //如果上下文没有被刷新过,调用子类刷新。(该方法由子类实现)
            onRefresh(wac);
        }

        if (this.publishContext) {
            // 发布此上下文作为Servlet上下文的一个属性
            String attrName = getServletContextAttributeName();
            getServletContext().setAttribute(attrName, wac);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
                        "' as ServletContext attribute with name [" + attrName + "]");
            }
        }

        return wac;
    }

FrameworkServlet和Spring框架紧紧相关,会将Spring上下文设置为父上下文,将自身上下文设置为Servlet上下文的一个属性。另外注意,这个类将doGet/doPost方法重写,最终都调用了抽象doServie()方法,交给子类实现。
继承这个类时需要注意重写doService/按自身需要onRefresh两个方法
这里写图片描述
DispatchServlet的onRefresh方法:

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);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值