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

来源:互联网 发布:最好的电子书软件 编辑:程序博客网 时间:2024/04/29 07:30

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);    }
1 0
原创粉丝点击