spring mvc 之 FrameworkServlet 源码解析

1,774 阅读2分钟

FrameworkServlet是spring mvc下一个setvlet的基类,它继承了HttpServletBean,HttpServletBean又继承了HttpServlet
通过 HttpServletBean 源码解析中我们了解到HttpServletBean重写了servlet的init()方法,在init()方法中调用了initServletBean(), initServletBean()是个空方法需要子类去实现它

FrameworkServlet做了一些什么事?

  • 实现HttpServletBean中的initServletBean(),在initServletBean()创建或者刷新WebApplicationCentext容器

protected final void initServletBean() throws ServletException {
    this.getServletContext().log("Initializing Spring " + this.getClass().getSimpleName() + " '" + this.getServletName() + "'");
    if (this.logger.isInfoEnabled()) {
        this.logger.info("Initializing Servlet '" + this.getServletName() + "'");
    }

    long startTime = System.currentTimeMillis();

    try {
    
        //初始化或者刷新WebApplicationContext容器
        this.webApplicationContext = this.initWebApplicationContext();
        this.initFrameworkServlet();
    } catch (RuntimeException | ServletException var4) {
        this.logger.error("Context initialization failed", var4);
        throw var4;
    }

    if (this.logger.isDebugEnabled()) {
        String value = this.enableLoggingRequestDetails ? "shown which may lead to unsafe logging of potentially sensitive data" : "masked to prevent unsafe logging of potentially sensitive data";
        this.logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails + "': request parameters and headers will be " + value);
    }

    if (this.logger.isInfoEnabled()) {
        this.logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " 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);
                }
                 //这个方法可以刷新WebApplicationContext中配置,
                this.configureAndRefreshWebApplicationContext(cwac);
            }
        }
    }

    if (wac == null) {
      //从ContextAttribute中查找WebApplicationContext
        wac = this.findWebApplicationContext();
    }

    if (wac == null) {
        //如果还是没有找到则会去创建一个WebApplicationContext
        wac = this.createWebApplicationContext(rootContext);
    }

   
    if (!this.refreshEventReceived) {
       //刷新WebApplicationContext配置,onRefresh需要子类去实现
        synchronized(this.onRefreshMononRefresh需要子类去实现itor) {
            this.onRefresh(wac);
        }
    }

    if (this.publishContext) {
    
        //将当前容器保存到ServletContext中
        String attrName = this.getServletContextAttributeName();
        this.getServletContext().setAttribute(attrName, wac);
    }

    return wac;
}

WebApplicationContext寻找以及创建包含以下几个步骤

  1. this.webApplicationContext不等于null,则判断当前webApplicationContext容器是否可用,不可用的情况下,判断是否设置了父容器,最后调用this.configureAndRefreshWebApplicationContext(cwac)刷新webApplicationContext配置
  2. webApplicationContext为空,则通过从web.xml配置中servlet参数查到对应的WebApplicationContext
  3. 如果依旧没有找到则创建webApplicationContext

configureAndRefreshWebApplicationContext

不管是单纯创建还是通过构造器注入,最终都会调用到configureAndRefreshWebApplicationContext()方法,configureAndRefreshWebApplicationContext()中调用了AbstractApplicationContext.refresh()刷新上下文环境,

AbstractApplicationContext.refresh()在最后一步调用finishRefresh()发布了ContextRefreshedEvent事件,则调用事件,从而FrameworkServlet监听到了ContextRefreshedEvent事件,则调用onRefresh()方法。

onRefresh()最后被DispatcherServlet所实现,初始化了它的九大组件

总结

  • HttpServletBean 覆盖 GenericServlet 的 init() 方法,该方法调用 initServletBean() 方法,该方法被 FrameworkServlet 覆盖
  • 在 FrameworkServlet 的 initServletBean() 方法中,它调用 initWebApplicationContext() 方法
  • 在该方法中,它检查 webApplicationContext 是否是 ConfigurableWebApplicationContext 的实例
  • 如果是,则调用 configureAndRefreshWebApplicationContext() 方法
  • 因为它在 webApplicationContext 上调用 refresh 方法
  • 查看 AbstractApplicationContext 中 refresh() 方法的实现,最后调用了 finishRefresh() 方法
  • 在该方法中它发布 ContextRefreshedEvent
  • 在 FrameworkServlet 中有实现 ApplicationListener 的私有类 ContextRefreshListener
  • 此类上的 onApplicationEvent() 方法调用 FrameworkServlet 的 onApplicationEvent() 方法
  • 在该方法中,它调用由 DispatcherServlet 覆盖的 onRefresh 方法