springmvc源码分析之一

springmvc其实就是对servlet的封装

看源码需要搞清楚一下几个问题

  • springmvc是如何和servlet整合
  • springmvc是如何与ioc整合

一、springmvc是如何与servlet整合

servlet 3.0 规范提到
servlet 规范提到
总结 : servlet容器在启动的时候回加载实现 ServletContainerInitializer 位置放到META-INF/services .他会回调里面的的方式,通过在类上面添加注解HandlesTypes(接口) 他可以是实现类,接口,抽象类。都会被加载。

The onStartup method of the ServletContainerInitializer will be invoked when the application is coming up before any of the servlet listener events are fired.

ServletContainerInitializer
这个意思: 实现类初始化

public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
			throws ServletException {
		List<WebApplicationInitializer> initializers = new LinkedList<>();
		if (webAppInitializerClasses != null) {
			for (Class<?> waiClass : webAppInitializerClasses) {
				// Be defensive: Some servlet containers provide us with invalid classes,
				// no matter what @HandlesTypes says...
				if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
						WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
					try {
						initializers.add((WebApplicationInitializer)
								ReflectionUtils.accessibleConstructor(waiClass).newInstance());
					}
					catch (Throwable ex) {
						throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
					}
				}
			}
		}

		if (initializers.isEmpty()) {
			servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
			return;
		}

		servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");

    // 在这里进行初始化处理
		AnnotationAwareOrderComparator.sort(initializers);
		for (WebApplicationInitializer initializer : initializers) {
			initializer.onStartup(servletContext);
		}
	}

初始化上下文
org.springframework.web.servlet.support.AbstractDispatcherServletInitializer#onStartup

@Override
	public void onStartup(ServletContext servletContext) throws ServletException {
		// 调用上下文加载器初始化类的onStartup方法
		super.onStartup(servletContext);
		// 注册DispatcherServlet
		registerDispatcherServlet(servletContext);
	}

org.springframework.web.context.AbstractContextLoaderInitializer#onStartup

public void onStartup(ServletContext servletContext) throws ServletException {
		registerContextLoaderListener(servletContext);
	}

org.springframework.web.context.AbstractContextLoaderInitializer#registerContextLoaderListener

protected void registerContextLoaderListener(ServletContext servletContext) {
		// 创建root容器
		WebApplicationContext rootAppContext = createRootApplicationContext();
		if (rootAppContext != null) {
			ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
			listener.setContextInitializers(getRootApplicationContextInitializers());
			// 把上下文加载监听器加载到servlet容器
			servletContext.addListener(listener);
		}
		else {
			logger.debug("No ContextLoaderListener registered, as " +
					"createRootApplicationContext() did not return an application context");
		}
	}

org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer#createRootApplicationContext

protected WebApplicationContext createRootApplicationContext() {
		// 定义根容器 @Service @Responsitory
		Class<?>[] configClasses = getRootConfigClasses();
		// 配置类是否为空
		if (!ObjectUtils.isEmpty(configClasses)) {
			AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
			context.register(configClasses);
			return context;
		}
		else {
			return null;
		}
	}

AnnotationConfigWebApplicationContext 类导航

org.springframework.web.servlet.support.AnnotationConfigDispatcherServletInitializerTests.MyAnnotationConfigDispatcherServletInitializer#getRootConfigClasses

protected Class<?>[] getRootConfigClasses() {
			return null;
		}

总结: 当servlet容器启动的是否首先会加载实现ServletContainerInitializer,然后通过注解 @HandlesTypes 解析出来改接口所有集成与实现类,抽象。然后调用 onStartup类。将注册接口相关的类通过参数的形式传递到该方法中,如果是实现类。就初始化,然后回调onStartup进行下一步操作。registerContextLoaderListener该方法主要做了创建根容器,并将根容器注册到ioc。 把上下文加载监听器加载到servlet容器(如果更容器存在,就把注册到servlet容器)

注册DispatchServlet )——(重点)

registerDispatcherServlet(servletContext);

 protected WebApplicationContext createServletApplicationContext() {
        // 创建基于注解的web应用上下文
		AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
		// 从子类实现中或者从@Configuration、@Component注解配置中获取配置类
		Class<?>[] configClasses = getServletConfigClasses();
		if (!ObjectUtils.isEmpty(configClasses)) {
	      // 注册@Configuration配置的配置加载类到AnnotationConfigWebApplicationContext
			context.register(configClasses);
		}
		return context;
	}

org.springframework.web.servlet.support.AnnotationConfigDispatcherServletInitializerTests.MyAnnotationConfigDispatcherServletInitializer#getServletConfigClasses

protected Class<?>[] getServletConfigClasses() {
			return new Class<?>[] {MyConfiguration.class};
		}

org.springframework.web.servlet.support.AnnotationConfigDispatcherServletInitializerTests.MyConfiguration

@Configuration
	public static class MyConfiguration {
 
		@Bean
		public MyBean bean() {
			return new MyBean();
		}
	}

注册派生@Configuration、@Component

protected FilterRegistration.Dynamic registerServletFilter(ServletContext servletContext, Filter filter) {
		// 获取filteName
		String filterName = Conventions.getVariableName(filter);
		// 添加filter到servlet容器
		Dynamic registration = servletContext.addFilter(filterName, filter);
        //  如果filter注册失败
		if (registration == null) {
			int counter = 0;
			while (registration == null) {
				if (counter == 100) {
					throw new IllegalStateException("Failed to register filter with name '" + filterName + "'. " +
							"Check if there is another filter registered under the same name.");
				}
				//添加filter#0 到servlet容器
				registration = servletContext.addFilter(filterName + "#" + counter, filter);
				counter++;
			}
		}

		registration.setAsyncSupported(isAsyncSupported());
		registration.addMappingForServletNames(getDispatcherTypes(), false, getServletName());
		return registration;
	}

总结:创建servlet上下文。注册dispatchServlet对象,同时注册过滤器。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值