Spring源码分析---springMVC

六、SpringMVC源码分析

1、DispatchServlet

前端控制器,请求处理逻辑的实现

2、HandlerMapping

处理器映射,为mvc中url路径与Controller对象的映射,DispatcherServlet就是基于此组件来寻找对应的Control。                          目前主流的三种mapping:                                                                                                                        BeanNameUrlHandlerMapping,基于ioc中beanName以 "/" 开头的Bean的映射
SimpleUrlHandlerMapping,基于手动配置 url 与controller映射
RequestMappingHandlerMapping,基于@RequestMapping注解配置对应的映射

annotation-driven默认添加的三种handler

3、HandlerAdapter

Springmvc 采用适配器模式来适配调用指定Handler,根据Handler的不同种类采用不同的。

Controller对应适配器SimpleControllerHandlerAdapter,标准控制器,返回ModelAndView
HttpRequestHandler对应适配器HttpRequestHandlerAdapter,业务自行处理 请求,不需要通过modelAndView转到视图
Servlet对应适配器SimpleServletHandlerAdapter,基于标准的servlet处理
HandlerMethod对应适配器RequestMappingHandlerAdapter,基于@RequestMapping对应方法处理

4、HandlerExecutionChain

处理器执行链

5、ViewResolver

视图解析器,找到应的Adapter 之后就会基于适配器调用业务处理,处理完之后业务方会返回一个 ModelAndView ,在去查找对应的视图进行处理。

6、View

具体解析视图, 获取对应View来解析生成Html并返回 

7、HandlerExceptionResolver

处理器异常解析器,用于指示当出现异常时 Spring mvc 该如何处理

8、HandlerInterceptor

处理器拦截器

 

web服务器启动tomcat首先会去加载web.xml配置文件

<servlet>  
<servlet-name>dispatcherServlet</servlet-name>  
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servletclass>  
<init-param>    
<param-name>contextConfigLocation</param-name>    
<param-value>classpath:spring-mvc.xml</param-value>  
</init-param>  
<load-on-startup>1</load-on-startup>
</servlet>

首先就实例化DispatcherServlet,在这里还配置了监听tomcat容器启动来初始化spring容器,ContextLoaderListener是spring框架中对ServletContextListener的一个实现,ServletContextListener依赖于sevlet容器,那么在tomcat启动的时候会调用contextInitialized方法来初始化。

另外如果没有配置ContextLoaderListener,在DispatcherServlet的父类FrameworkServlet会去初始化spring容器。

if (wac == null) {
// No context instance is defined for this servlet -> create a local one
//如果没有配置ContextLoaderListener加载容器,那么servlet也会加载容器
wac = createWebApplicationContext(rootContext);
}

在createWebApplicationContext会调用configureAndRefreshWebApplicationContext初始化容器,后面就是调用spring容器初始化代码。

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
		if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
			// The application context id is still set to its original default value
			// -> assign a more useful id based on available information
			if (this.contextId != null) {
				wac.setId(this.contextId);
			}
			else {
				// Generate default id...
				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
						ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
			}
		}

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

		// The wac environment's #initPropertySources will be called in any case when the context
		// is refreshed; do it eagerly here to ensure servlet property sources are in place for
		// use in any post-processing or initialization that occurs below prior to #refresh
		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
		}

		postProcessWebApplicationContext(wac);
		applyInitializers(wac);
		//初始化容器
		wac.refresh();
	}

spring容器启动就会去加载相应的配置文件,创建bean。

<context:component-scan base-package="xxx" />
 <!-- 注解驱动 --> 
<!--自动向ioc注册了RequestMappingHandlerMapping与BeanNameUrlHandlerAdapter-->
<mvc:annotation-driven/>

component-scan在这里不在讲,我们现在主要看<mvc:annotation-driven/>,以前提过会有相应的命名空间解析类来解析。

public class MvcNamespaceHandler extends NamespaceHandlerSupport {

	@Override
	public void init() {
		registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
		registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
		registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
		registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
		registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
		registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
		registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
		registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
		registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
		registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
		registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
		registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());
		registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());
	}

}

我们来看AnnotationDrivenBeanDefinitionParser类的parse方法,在这里面会注册很多相应的spring自带的bean,比如RequestMappingHandlerMapping。

RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);

........

MvcNamespaceUtils.registerDefaultComponents(context, source);

可以看到已经把RequestMappingHandlerMapping注册到容器了,还有一些默认的组件

public static void registerDefaultComponents(ParserContext parserContext, @Nullable Object source) {
		registerBeanNameUrlHandlerMapping(parserContext, source);
		registerHttpRequestHandlerAdapter(parserContext, source);
		registerSimpleControllerHandlerAdapter(parserContext, source);
		registerHandlerMappingIntrospector(parserContext, source);
	}

RequestMappingHandlerMapping是实现了InitialzingBean接口的,而这个类的父类AbstractHandlerMethodMapping的afterPropertiesSet方法是整个映射关系建立的入口

public void afterPropertiesSet() {
                 //建立映射关系
		initHandlerMethods();
		int total = this.getHandlerMethods().size();
		if ((logger.isTraceEnabled() && total == 0) || (logger.isDebugEnabled() && total > 0) ) {
			logger.debug(total + " mappings in " + formatMappingName());
		}
	}

而initHandlerMethods是主要实现映射关系的方法

protected void initHandlerMethods() {
		String[] beanNames = obtainApplicationContext().getBeanNamesForType(Object.class);

		for (String beanName : beanNames) {
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
				Class<?> beanType = null;
				try {
					beanType = obtainApplicationContext().getType(beanName);
				}
				catch (Throwable ex) {
					// An unresolvable bean type, probably from a lazy bean - let's ignore it.
					if (logger.isTraceEnabled()) {
						logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
					}
				}
				if (beanType != null && isHandler(beanType)) {
					detectHandlerMethods(beanName);
				}
			}
		}
		handlerMethodsInitialized(getHandlerMethods());
	}
 

查找Controller下所有带有@RequestMapping注解的方法,最后注册HandlerMethod 

protected void detectHandlerMethods(final Object handler) {
		Class<?> handlerType = (handler instanceof String ?
				obtainApplicationContext().getType((String) handler) : handler.getClass());

		if (handlerType != null) {
			final Class<?> userType = ClassUtils.getUserClass(handlerType);
			Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
					(MethodIntrospector.MetadataLookup<T>) method -> getMappingForMethod(method, userType));
			if (logger.isTraceEnabled()) {
				logger.trace(formatMappings(userType, methods));
			}
			methods.forEach((key, mapping) -> {
				Method invocableMethod = AopUtils.selectInvocableMethod(key, userType);
				registerHandlerMethod(handler, invocableMethod, mapping);
			});
		}
	}

查找所有带@RequestMapping的方法,并存放到Map<Method,RequestMappingInfo>中,RequestMappingInfo中的patternsCondition属性就是我们解析注解中的url

我们知道当一个请求来是,会执行servlet的doService方法,doService()中的核心逻辑由doDispatch()实现

doDispatch(request, response);

主要看doDispatch方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				// 判断是否是文件上传
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// Determine handler for the current request.
				// 返回 HandlerExecutionChain  执行链 (Handler HandlerInterceptors )
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				// 返回handler对应的适配器
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					// 实现LastModified接口的getLastModified方法,返回一个时间戳,请求中会增加If-Modified-Since参数
					// 通过checkNotModified比较两次请求时间戳,如果一致,就直接返回 http响应头,
					// 静态资源取浏览器缓存,status code 变为304
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
				// 拦截器前置方法
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
				// 调用业务逻辑
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				//用于管理异步请求处理的中心类,主要用作SPI,通常不直接由应用程序类使用。
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);

				//拦截器后置方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			// 将modelAndView交给视图解析器处理
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

在方法内mappedHandler = this.getHandler(processedRequest)就是根据当前的请求去拿一个Handler,这个Handler就是我们写的控制器(controller),也就是去HandlerMapping集合遍历寻找。

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping mapping : this.handlerMappings) {
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

接下来我们通过HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler())就是去拿相应的适配器类,前面有对照过。拿到控制器适配器中执行控制器。

接下来就是执行拦截器的逻辑了

if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
				// 调用业务逻辑
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				//用于管理异步请求处理的中心类,主要用作SPI,通常不直接由应用程序类使用。
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);

				//拦截器后置方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}

如果你有ModelAndView,就返回一个ModelAndView.然后返回给试图对象,然后把视图对象交给视图解析器,去渲染,最后响应给用户。

将modelAndView交给视图解析器处理

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException)

 先会判断是否有异常,有异常会进入异常处理机制,如果没有就会去渲染视图

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {

		boolean errorView = false;

		// 异常判断
		if (exception != null) {
			if (exception instanceof ModelAndViewDefiningException) {
				logger.debug("ModelAndViewDefiningException encountered", exception);
				mv = ((ModelAndViewDefiningException) exception).getModelAndView();
			}
			else {
				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
				//异常处理机制,处理完成之后返回errorView 跳转到异常视图
				mv = processHandlerException(request, response, handler, exception);
				errorView = (mv != null);
			}
		}

		// Did the handler return a view to render?
		if (mv != null && !mv.wasCleared()) {
			//渲染视图
			render(mv, request, response);
			if (errorView) {
				WebUtils.clearErrorRequestAttributes(request);
			}
		}
		else {
			if (logger.isTraceEnabled()) {
				logger.trace("No view rendering, null ModelAndView returned.");
			}
		}

		if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
			// Concurrent handling started during a forward
			return;
		}
		// 调用拦截器 afterCompletion 方法
		if (mappedHandler != null) {
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值