Spring MVC源码剖析 一、DispatcherServlet初始化源码剖析

本文深入探讨Spring MVC的DispatcherServlet初始化过程,从创建到启动Spring容器,揭示其在web.xml配置中的必要性。文章详细分析了DispatcherServlet继承链,以及init()、initServletBean()和initWebApplicationContext()等关键方法,最终解释了如何生成和启动Spring容器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  使用Spring MVC的时候,每次都要在web.xml中初始化一个DispatcherServlet,这是为什么呢?因为我们需要DispatcherServlet来将Spring容器启动起来,启动完成后,由DispatcherServlet来接收请求并分发。

  首先。DispatcherServlet 继承 FrameworkServlet,FrameworkServlet 继承 HttpServletBean ,HttpServletBean 继承 HttpServlet ,即原生的 HttpServlet 。

  我们下面看一下DispatcherServlet的初始化过程:

  系统new了 DispatcherServlet 了之后,会调用其init() 方法,即 HttpServletBean 的init方法:

@Override
	public final void init() throws ServletException {

		// 从配置文件中读取出配置,比如在web.xml中读取的 name为contextConfigLocation,value为 classpath*:servlet-context.xml
		try {
			PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
			BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
			ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
			bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
			initBeanWrapper(bw);
			bw.setPropertyValues(pvs, true);
		}
		catch (BeansException ex) {
			logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
			throw ex;
		}

		// 此方法非常非常重要,初始化容器,与web中的相关映射。
		initServletBean();

	}

继续看 FrameworkServlet中的 initServletBean() 方法:

	protected final void initServletBean() throws ServletException {
		

		long startTime = System.currentTimeMillis();

		try {
			// 此方法非常重要,初始化了一个 ApplicationContext 容器,完成了beanDefinition的生成,根据beanDefinition生成bean的操作
 // 在bean生成完成之后,此方法还会初始化 mvc 中的 HanderMapping、handerAdapter等一系列组件
			this.webApplicationContext = initWebApplicationContext();

		}
		
		. . . 

		if (this.logger.isInfoEnabled()) {
			// 还会计时,我们平常的计时就在这里来完成的
			long elapsedTime = System.currentTimeMillis() - startTime;
			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
					elapsedTime + " ms");
		}
	}

   再看一下 initWebApplicationContext() 方法:

	protected WebApplicationContext initWebApplicationContext() {
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;

		. . . 
		
		if (wac == null) {
			// 此为创建一个 WebApplicationContext ,并调用其 refresh() 方法来生成容器
			wac = createWebApplicationContext(rootContext);
		}

		if (!this.refreshEventReceived) {
			// 此为调用自身的 onRefresh() 方法,来初始化  mvc 中的 HanderMapping、handerAdapter等一系列组件
			onRefresh(wac);
		}

		. . .
		return wac;
	}

  首先看一下 createWebApplicationContext() ,看其实如何来生成一个 容器 的:

	protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
		

		// 先使用 BeanUtils 生成了一个 ApplicationContext,注意我们生成的是 XmlWebApplicationContext
		ConfigurableWebApplicationContext wac =
				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

		wac.setEnvironment(getEnvironment());
		wac.setParent(parent);

		// 此为将 context 文件的路径注入进去,比如我们之前使用的xmlClassPathApplicationContext,就需要一个 xml 文件的路径,现在也是一样的,通过这个将其注入进去
		wac.setConfigLocation(getContextConfigLocation());

		// 最后调用方法将其初始化完成
		configureAndRefreshWebApplicationContext(wac);

		return wac;
	}

	protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {

		. . .

		wac.setServletContext(getServletContext());
		wac.setServletConfig(getServletConfig());
		wac.setNamespace(getNamespace());
		wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
		}

		postProcessWebApplicationContext(wac);
		applyInitializers(wac);

		// 注意,最后非常重要!调用了 applicationContxt的 refresh() 方法,先根据ConfigLocation得到Resource,在根据Resource生成beanDefinition,最后根据 beanDefinition 生成bean。
		wac.refresh();
	}

  至此,Spring容器启动。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值