SpringMVC(二)-ContentLoaderListener去创建Root web容器

6 篇文章 0 订阅

前言

今天继续上一篇文章,上篇文章中只要将了 我们SpringMVC 中的ContextLoaderListener 是怎么被加入监听 然后tomact又是怎么去加载web.config配置的 最后怎么去调用ContextLoaderListener#contextInitialized方法的 不清楚的小伙伴 可以回到上篇文章 去看下

ContextLoaderListener

我们从前文中分析得到 程序启动的时候 是调用了contextInitialized的方法
那我就从这个方法入手 看看到底执行了什么

    @Override
	public void contextInitialized(ServletContextEvent event) {
		initWebApplicationContext(event.getServletContext());
	}

从代码中 我们可以看出 这个方法时 重写了父类的方法 initWebApplicationContext方法 我们跟进去 可以看到 是父类ContentLoader的方法 从名字我们也可以看到 就是一个初始化webApplicationContenxt的

ServletContextEvent 我们从上篇文章中 也可以看出 其实就是包装了下ServletContext,ServletContextEvent.getServletContext()方法 最终就是返回的ServletContext对象,如果对ServletContext不清楚的 也可以去上篇文章中去看下 他是在ContentConfig中 处理上下文的方法lifecycleEvent中去创建的,每个web应用 只会分配一个ServletContext 可以获取应用的上下文

好的,继续回到initWebApplicationContext方法中

initWebApplicationContex

下面我截取一些核心的代码

    /**
     * 这边的英文注释 写的还是很清楚的 自己读一遍应该能看懂  我就不翻译了 怕词不答意
	 * Initialize Spring's web application context for the given servlet context,
	 * using the application context provided at construction time, or creating a new one
	 * according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
	 * "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
	 */
	public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
			/**
			* 这个是判断了下context是否为null 如果使用的构造函数 直接传入一个webApplicationContext 我们就不用创建了
			* 当然我们这边我们初始化的时候 并没有传入 所以这边context是null 所以要走createWebApplicationContext流程
			*/
			if (this.context == null) {
				this.context = createWebApplicationContext(servletContext);
			}
			// 这边做的就是 如果上下文没有刷新 就进行配置和刷新
			// ConfigurableWebApplicationContext 这边的默认配置的实现是    XmlWebApplicationContext  这个可以在  ContextLoader.properties 的配置里面可以去 找到  
			if (this.context instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
				if (!cwac.isActive()) {
				    // 这边判断了下 当前容器 没有父容器 就创建父容器 并且设置
					if (cwac.getParent() == null) {
						ApplicationContext parent = loadParentContext(servletContext);
						cwac.setParent(parent);
					}
					configureAndRefreshWebApplicationContext(cwac, servletContext);
				}
			}
			<!--这二就是设置了当前webApplicationContext 到ServletConetext的属性中-->
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

            <!--获取当前的类加载器-->
			ClassLoader ccl = Thread.currentThread().getContextClassLoader();
			if (ccl == ContextLoader.class.getClassLoader()) {
				currentContext = this.context;//这边 为什么要这个判断  个人感觉是因为 context在初始化时候 可以又传入一个webApplicationConetext 而这个类可能是又Servlet容器 加载的 这样就可能会导致类加载器是不一样的  所以不能给currentContext赋值
			}
			else if (ccl != null) {
			<!--这边是放到一个map 集合里面  存放着 对应类加载器下的web容器-->
				currentContextPerThread.put(ccl, this.context);
			}
			return this.context;
	}

initWebApplicationContex 方法主要做的就是创建root web容器 并对其进行刷新 读取的配置 从注释中也可以看到 就是context-para里面param-name:contextConfigLocation的value
这个就能看出 我们web.config里面的配置了 就是为了设置root webApplicatonContext的,

createWebApplicationContext

先来下代码

    protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
        <!--这边就是获取了contextClass-->
		Class<?> contextClass = determineContextClass(sc);
		<!--做了下判断 是否是继承了ConfigurableWebApplicationContext的 代码写的很是很严谨的  哈哈-->
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
					"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
		}
		return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);//这个就是通过反射创建一个WebApplicationContext对象 
	}
    
    protected Class<?> determineContextClass(ServletContext servletContext) {
    <!--这个配置就是读取我们web.config里面的contextpara 是否配置了contextClass 当然了 正常的情况下我们都没有配置 所有 逻辑一般走的都是下面的部分-->
		String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
		if (contextClassName != null) {
			try {
				return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException(
						"Failed to load custom context class [" + contextClassName + "]", ex);
			}
		}
		else {
		    <!--这个就是获取默认的配置  这个默认配置的是XmlWebApplicationContext 配置是的ContextLoader.properties 中-->
			contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
			try {
				return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException(
						"Failed to load default context class [" + contextClassName + "]", ex);
			}
		}
	}

determineContextClass 方法就是获取我们的conetext类 一般都是读取的默认配置里的XmlWebApplicationContext,

总结

这篇文章很短 主要讲了的是怎么创建WebApplicationConetext的 当看到一个configureAndRefreshWebApplicationContext#refresh 就能串联起来 我们Spring 中IOC的初始化流程 这个找时间 聊一波 这个有点儿长。。。

好的 后面一篇文章 我们主要聊下 DispatcherServlet

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值