springmvc第二篇 --FrameworkServlet

//从HttpServletBean中得知,initServletBean是FrameworkServlet的入口方法

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
	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**
        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);
                    }
                    this.configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
        **//当WebApplicationContext存在于servletContext中时,通过attributeName获取**
        if (wac == null) {
            wac = this.findWebApplicationContext();
        }
        if (wac == null) {
        	**//若果还没有则创建一个**
            wac = this.createWebApplicationContext(rootContext);
        }
        **//容器没有刷新时调用onRefresh方法,此方法在字类DispatcherServlet实现**
        if (!this.refreshEventReceived) {
            synchronized(this.onRefreshMonitor) {
                this.onRefresh(wac);
            }
        }
        if (this.publishContext) {
	        //将WebApplicationContext存入到servletContext中
            String attrName = this.getServletContextAttributeName();
            this.getServletContext().setAttribute(attrName, wac);
        }
        return wac;
    }

## initWebApplicationContext方法做了三件事:

 1. 获取spring容器的跟容器rootContext 	
 2. 设置WebApplicationContext并调用onRefresh
 3. 将WebApplicationContext设置到servletContext中

## 获取spring的根容器
	默认情况下,spring会将自己的容器设置成servletContext类型,默认的跟容器key是(ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";)
	所有获取跟容器调用servletContext的getAttribute就可以
	getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
	**获取WebApplicationContext的三种**
 1. 第一种是在构造方法中以已经传递WebApplicationContext
 2. 第二种是WebApplicationContext已经在servletContext中了
 3. 第三种是自己创建一个(正常情况使用这种方式),代码如下:


 protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
		 **//获取创建类型**
        Class<?> contextClass = this.getContextClass();
        **//检查创建类型**
        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 {
          	**//具体创建**
            ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
            wac.setEnvironment(this.getEnvironment());
            wac.setParent(parent);
            String configLocation = this.getContextConfigLocation();
            **//将设置的configCotextLocation参数设置给wac**
            if (configLocation != null) {
                wac.setConfigLocation(configLocation);
            }
            this.configureAndRefreshWebApplicationContext(wac);
            return wac;
        }
    }
```protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
        if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
            if (this.contextId != null) {
                wac.setId(this.contextId);
            } else {
                wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(this.getServletContext().getContextPath()) + '/' + this.getServletName());
            }
        }

        wac.setServletContext(this.getServletContext());
        wac.setServletConfig(this.getServletConfig());
        wac.setNamespace(this.getNamespace());
		**//给wac设置监听器**
        wac.addApplicationListener(new SourceFilteringListener(wac, new FrameworkServlet.ContextRefreshListener()));
        ConfigurableEnvironment env = wac.getEnvironment();
        if (env instanceof ConfigurableWebEnvironment) {
            ((ConfigurableWebEnvironment)env).initPropertySources(this.getServletContext(), this.getServletConfig());
        }

        this.postProcessWebApplicationContext(wac);
        this.applyInitializers(wac);
        wac.refresh();
    }
	**首先通过getContextClass获取创建类型,然后检查属不属于ConfigurableWebApplicationContext类型,不属于就抛出异常。接下来通过BeanUtils.instantiateClass(contextClass)进行创建wac对象。
	在configureAndRefreshWebApplicationContext方法给wac添加了监听器。**
	        wac.addApplicationListener(new SourceFilteringListener(wac, new FrameworkServlet.ContextRefreshListener()));
	**SourceFilteringListener根据数据的参数进行选择,所以实际监听的是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;
        synchronized(this.onRefreshMonitor) {
            this.onRefresh(event.getApplicationContext());
        }
    }
**ContextRefreshListener是FrameworkServlet 内部类,在接收到消息的时候会调用一下内部的onRefresh方法,并将refreshEventReceived设置为true,表示已经refresh过了。**

**后面会根据refreshEventReceived状态判断是否需要refresh。**
  if (!this.refreshEventReceived) {
            synchronized(this.onRefreshMonitor) {
                this.onRefresh(wac);
            }
        }
 **所以不管怎么样,onRefresh指挥调用一次,字类DispatcherServlet就是通过重写这个方法实现初始化的。**
}

参考资料:看透springmvc源码

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值