SpringMVC框架的一些底层

来源:互联网 发布:php软件下载 编辑:程序博客网 时间:2024/05/16 04:03

SpringMVC框架的一些底层


  • SpringMVC的init()
    SpingMVC加载过程
    这里写图片描述

类结构图
这里写图片描述

首先看一下这个结构图,DispatcherServlet是SpringMVC的核心控制器,他遵循了Servlet规范.
这里写图片描述

虽然现在是一个高大上的框架,但是这三个重要方法肯定是不能忽视的..

第一步:初始化位于HttpServletBean当中的init()方法,因为他是对接Servlet容器体系中传入进来的参数.首先先看一下HttpServletBean中的init()方法:

    public final void init() throws ServletException {        if(this.logger.isDebugEnabled()) {            this.logger.debug("Initializing servlet '" + this.getServletName() + "'");        }        //配置文件的信息在ServletConfig中,用这个来初始化SpringMVC框架.        //requiredProperties,必须的参数属性,如果没有,抛异常.        PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);        if(!pvs.isEmpty()) {            try {                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);            } catch (BeansException var4) {                if(this.logger.isErrorEnabled()) {                    this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4);                }                throw var4;            }        }        //模版方法,让子类FrameworkServlet具体实现        //初始化SpringMVC框架的Bean组件  Controller... 九大组件        this.initServletBean();        if(this.logger.isDebugEnabled()) {            this.logger.debug("Servlet '" + this.getServletName() + "' configured successfully");        }    }

第二步:初始化Bean组件

    protected final void initServletBean() throws ServletException {        .....        try {            //初始化Bean , 构造SpringMVC自己的上下文            this.webApplicationContext = this.initWebApplicationContext();            this.initFrameworkServlet();        }         ......        }    }

获取Spring的根上下文.
根据当前的SpringMVC上下文:
不为空,进行设置双亲环境,刷新(将SpingMVC上下文激活);
为空,创建SpringMVC上下文,设置双亲环境,配置信息载入,刷新(将SpingMVC上下文激活).

    //构造SpringMVC的上下文环境    protected WebApplicationContext initWebApplicationContext() {        //通过工具类获取根上下文环境,请注意:1是通过ServletContext拿的,所以再   次印证了外层是ServletContext,里层是一个root也就是WebApplicationContext的上下文环境.此时还没有SpringMVC的上下文.        WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());        WebApplicationContext wac = null;        if(this.webApplicationContext != null) {            wac = this.webApplicationContext;            //如果是ConfigurableWebApplicationContext这个的一个实现类,强转,然后判断是否激活            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();            //这里将SpingMVC的上下文环境设置到了ServletContext上,所以我们才可以根据ServletContext获取SpringMVC上下文.            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;    }

在FrameworkServlet中有个内部类ContextRefreshListener 用于监听

    private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {        private ContextRefreshListener() {        }        public void onApplicationEvent(ContextRefreshedEvent event) {            FrameworkServlet.this.onApplicationEvent(event);        }    }
    public void onApplicationEvent(ContextRefreshedEvent event) {        this.refreshEventReceived = true;        this.onRefresh(event.getApplicationContext());    }

initWebApplicationContext方法,会根据refreshEventReceived标志来判断是否要远行onRefresh方法.

//创建一个WebApplicationContext    protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {        //获取创建类型        Class<?> contextClass = this.getContextClass();        if(this.logger.isDebugEnabled()) {            this.logger.debug("Servlet with name '" + this.getServletName() + "' will try to create custom WebApplicationContext context of class '" + contextClass.getName() + "', using parent context [" + parent + "]");        }        if(!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {            throw new ApplicationContextException("Fatal initialization error in servlet with name '" + this.getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext");        } else {        //这里使用的DEFAULT_CONTEXT_CLASS设置为XmlWebApplicationContext.class,所以DispatcherServlet中使用的上下文是XmlWebApplicationContext            ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);            wac.setEnvironment(this.getEnvironment());            //配置双亲上下文,就是再ContextLoader中建立的上下文            wac.setParent(parent);            //将contextConfigLocation 参数传给wac,默认传入WEB-INFO/[ServletName]-servlet.xml (配置文件的路径)            wac.setConfigLocation(this.getContextConfigLocation());            //刷新当前上下文            this.configureAndRefreshWebApplicationContext(wac);            return wac;        }    }

总结:
1.获取Spring的根容器rootContext . (获取根据容器的原理是默认情况下Spring会将自己的容器设置成ServletContext的属性,默认根容器的key 定义在org.springframework.web.context.WebApplicationContext 中,String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE =WebApplicationContext.class.getName() + “.ROOT” , 所以获取根容器只需要调用ServletContext的getAttribute就可以了 ServletContext getAttribute(“org.springframework.web.context.WebApplicationContext.ROOT”))
2.设置WebApplicationContext并根据情况调用,onRefresh方法.(设置WebApplication一共有三种方法,第一种是构造方法中传入WebApplication参数,主要用于Servlet3.0以后的环境中,在Servlet3.0之后,可以在程序中用ServletContext.addServlet方式注册Servlet,这时就可以新建FrameworkServlet 第二种方法是WebApplicationContext已经在ServletContext中了,这时只需要在配置Servlet的时候将ServletContext中的webApplicationContext的name配置到contextAttribute上 第三种是前两种方法都无效的情况下自己创建一个,正常情况下就用的这种方式,创建过程在createWebApplicationContext中)

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

初始化SpingMVC上下文环境的九大组件…

    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);    }

这里写图片描述

  • SpringMVC的service()