Spring源码学习(5)- springmvc解析

匆匆过客 提交于 2020-02-25 15:50:46

介绍

SpringMvc是基于servlet规范来完成的一个请求详情模块,也是spring中比较大的一个模块。springmvc使用有两种方式,一种是配置文件的形式;另一个就是注解的形式,这种方法采用的是约定大于配置的方式。完成这个过程,springmvc要解决两个问题。

1.取代web.xml配置

springmvc借助servlet中的一个规范,来完成这个事情

当servlet容器启动的时候,会根据spi规范,在家META-INF/services文件夹里面的javax.servlet.ServletContainerInitializer文件,这个文件会实现javax.servlet.ServletContainerInitializer接口。

这个类在启动时,被servlet容器实例化,然后调用 onStartup 方法,并且servlet容器会收集实现了类上 @HandlesTypes 注解里面的接口的类,并作为入参(Set)传入到onStartup方法中,就可以拿到对应的class进行操作了,接下来看到方法中的 onStartup 方法

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {

	@Override
	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);
		}
	}

}

onStartup ():AbstractDispatcherServletInitializer这个类中的
代码分为两部分,一部分是调用父类的onStartup方法,另一部分就是registerDispatcherServlet

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
	super.onStartup(servletContext);
	//注册DispatcherServlet
	registerDispatcherServlet(servletContext);
}

super.onStartup()方法

这个方法作用是创建spring容器的上下文对象,存入到ContextLoaderListener对象中,最后存入servletContext中

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

/**
 * Register a {@link ContextLoaderListener} against the given servlet context. The
 * {@code ContextLoaderListener} is initialized with the application context returned
 * from the {@link #createRootApplicationContext()} template method.
 * @param servletContext the servlet context to register the listener against
 */
protected void registerContextLoaderListener(ServletContext servletContext) {

	// 创建spring上下文,注册了SpringContainer
	WebApplicationContext rootAppContext = createRootApplicationContext();
	if (rootAppContext != null) {
		// 创建监听器
		/*
			形如这种配置
		* <listener>
			  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
			<!--<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>-->
		  </listener>
		*
		* */
		ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
		listener.setContextInitializers(getRootApplicationContextInitializers());
		servletContext.addListener(listener);
	}
	else {
		logger.debug("No ContextLoaderListener registered, as " +
				"createRootApplicationContext() did not return an application context");
	}
}

createRootApplicationContext():
创建spring上下文,上下文就是收集各种bean的信息的容器,有两种收集方式
一种是配置文件收集
另一种则是注解方式收集,注解方式需要需要配置扫描器(@ComponentScan)去扫描项目中需要扫描入容器的bean。

在这个方法中,有个getRoowConfigClasses(),这就需要我们自己写一个类,继承AbstractAnnotationConfigDispatcherServletInitializer类,重写这个方法,将扫描器提供给上下文对象

@Override
@Nullable
protected WebApplicationContext createRootApplicationContext() {
	Class<?>[] configClasses = getRootConfigClasses();
	if (!ObjectUtils.isEmpty(configClasses)) {
		AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
		context.register(configClasses);
		return context;
	}
	else {
		return null;
	}
}

然后将上下文对象设置到ContextLoaderListener监听器对象中,最后把监听器对象设置到servletContext中

if (rootAppContext != null) {
	// 创建监听器
	/*
		形如这种配置
	* <listener>
		  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
		<!--<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>-->
	  </listener>
	*
	* */
	ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
	listener.setContextInitializers(getRootApplicationContextInitializers());
	servletContext.addListener(listener);
}
else {
	logger.debug("No ContextLoaderListener registered, as " +
			"createRootApplicationContext() did not return an application context");
}

registerDispatcherServlet()方法

这个方法,作用是实例化DispatcherServlet对象
主要就是两个createXXX方法来创建springmvc上下文跟servlet对象
创建springmvc上下文方法,跟创建spring上下文基本一致,都需要自己定义一个扫描器来扫描生成上下文。
然后根据上下文创建servlet对象

protected void registerDispatcherServlet(ServletContext servletContext) {
	String servletName = getServletName();
	Assert.hasLength(servletName, "getServletName() must not return null or empty");

	// 创建springmvc的上下文,注册了MvcContainer类
	WebApplicationContext servletAppContext = createServletApplicationContext();
	Assert.notNull(servletAppContext, "createServletApplicationContext() must not return null");

	// 创建DispatcherServlet
	FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
	Assert.notNull(dispatcherServlet, "createDispatcherServlet(WebApplicationContext) must not return null");
	dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());

	ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
	if (registration == null) {
		throw new IllegalStateException("Failed to register servlet with name '" + servletName + "'. " +
				"Check if there is another servlet registered under the same name.");
	}

	/*
	* 	如果该元素的值为负数或者没有设置,则容器会当Servlet被请求时再加载。
		如果值为正整数或者0时,表示容器在应用启动时就加载并初始化这个servlet,
		值越小,servlet的优先级越高,就越先被加载
	* */
	registration.setLoadOnStartup(1);
	registration.addMapping(getServletMappings());
	registration.setAsyncSupported(isAsyncSupported());

	Filter[] filters = getServletFilters();
	if (!ObjectUtils.isEmpty(filters)) {
		for (Filter filter : filters) {
			registerServletFilter(servletContext, filter);
		}
	}

	customizeRegistration(registration);
}

到此为止一共有spring跟springmvc上下文,分别存放在ContextLoaderListener对象跟DispatcherServlet中

启动spring容器

监听器 ContextLoaderListener 的启动
ContextLoaderListener类的 contextInitialized 方法

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

在这里插入图片描述
DispatcherServlet的启动
servlet要完成spring容器的启动,只能在init方法里面完成,所以需要找到此方法
DispatcherServlet 的父类 HttpServletBean 中找到init()方法,主要看方法里面的 initServletBean 方法

public final void init() throws ServletException {

	// Set bean properties from init parameters.
	PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
	if (!pvs.isEmpty()) {
		try {
			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) {
			if (logger.isErrorEnabled()) {
				logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
			}
			throw ex;
		}
	}

	// Let subclasses do whatever initialization they like.
	initServletBean();
}

initServletBean()

protected final void initServletBean() throws ServletException {
		getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
	if (logger.isInfoEnabled()) {
		logger.info("Initializing Servlet '" + getServletName() + "'");
	}
	long startTime = System.currentTimeMillis();

	try {
		this.webApplicationContext = initWebApplicationContext();
		initFrameworkServlet();
	}
	catch (ServletException | RuntimeException ex) {
		logger.error("Context initialization failed", ex);
		throw ex;
	}
	if (logger.isInfoEnabled()) {
		logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
	}
}

initWebApplicationContext()
1.获取spring上下文对象

protected WebApplicationContext initWebApplicationContext() {
	// 这里会从servletContext中获取到父容器,就是通过监听器加载的容器 (spring上下文)
	WebApplicationContext rootContext =
			WebApplicationContextUtils.getWebApplicationContext(getServletContext());
	WebApplicationContext wac = null;
	
	// 代码有省略......
	return wac;
}

在这里插入图片描述
在这里插入图片描述
2.设置springmvc上下文的父上下文(spring上下文)对象

if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
	wac = this.webApplicationContext;
	if (wac instanceof ConfigurableWebApplicationContext) {
		ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
		if (!cwac.isActive()) {
			// The context has not yet been refreshed -> provide services such as
			// setting the parent context, setting the application context id, etc
			if (cwac.getParent() == null) {
				// The context instance was injected without an explicit parent -> set
				// the root application context (if any; may be null) as the parent
				cwac.setParent(rootContext);
			}
			// 容器加载
			configureAndRefreshWebApplicationContext(cwac);
		}
	}
}

3.容器加载,进行refresh()
在这里插入图片描述
到此,springmvc就使用了servlet规范,来完成取代web.xml的工作,并启动容器

2.取代springmvc.xml配置

使用**@EnableWebMvc** 即可

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

该注解会导入类DelegatingWebMvcConfiguration,其父类为WebMvcConfigurationSupport
WebMvcConfigurationSupport这个类会完成很多组件的实例化,HandlerMapping,HandlerAdapter等,都是通过@Bean方式

请求之间建立映射关系

在Hanldermapping类实例化的时候,就会完成url和method的映射关系,要根据一个请求能够唯一找到一个类和一个方法

主要逻辑都在createRequestMappingHandlerMapping()方法中

@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
	RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
	mapping.setOrder(0);
	mapping.setInterceptors(getInterceptors());
	mapping.setContentNegotiationManager(mvcContentNegotiationManager());
	mapping.setCorsConfigurations(getCorsConfigurations());

	PathMatchConfigurer configurer = getPathMatchConfigurer();

	Boolean useSuffixPatternMatch = configurer.isUseSuffixPatternMatch();
	if (useSuffixPatternMatch != null) {
		mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
	}
	Boolean useRegisteredSuffixPatternMatch = configurer.isUseRegisteredSuffixPatternMatch();
	if (useRegisteredSuffixPatternMatch != null) {
		mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
	}
	Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
	if (useTrailingSlashMatch != null) {
		mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
	}

	UrlPathHelper pathHelper = configurer.getUrlPathHelper();
	if (pathHelper != null) {
		mapping.setUrlPathHelper(pathHelper);
	}
	PathMatcher pathMatcher = configurer.getPathMatcher();
	if (pathMatcher != null) {
		mapping.setPathMatcher(pathMatcher);
	}
	Map<String, Predicate<Class<?>>> pathPrefixes = configurer.getPathPrefixes();
	if (pathPrefixes != null) {
		mapping.setPathPrefixes(pathPrefixes);
	}

	return mapping;
}

createRequestMappingHandlerMapping
创建RequestMappingHandlerMapping类,其父类的父类的父类AbstractHandlerMethodMapping,实现了InitailizingBean接口,所以在RequestMappingHandlerMapping实例化后,会调用afterPropertiesSet()方法


1.afterPropertiesSet()

public void afterPropertiesSet() {
	initHandlerMethods();
}

2.initHandlerMethods()

protected void initHandlerMethods() {
	for (String beanName : getCandidateBeanNames()) {
		if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
			processCandidateBean(beanName);
		}
	}
	handlerMethodsInitialized(getHandlerMethods());
}

3.processCandidateBean()

protected void processCandidateBean(String beanName) {
	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);
		}
	}
	// 如果类上面有@Controller注解或者@RequestMapping注解
	if (beanType != null && isHandler(beanType)) {
		// 建立uri和method的映射关系
		detectHandlerMethods(beanName);
	}
}

4.detectHandlerMethods()
能进来这个方法的类,都是有@Controller或者@RequestMapping注解的

这个方法可分为两个部分

  • 获取方法和对象上的@RequestMapping注解属性封装对象的映射关系(上半部分)
// 获取方法对象和方法上面的@RequestMapping注解属性封装对象的映射关系
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
	(MethodIntrospector.MetadataLookup<T>) method -> {
		try {
			return getMappingForMethod(method, userType);
		}
		catch (Throwable ex) {
			throw new IllegalStateException("Invalid mapping on handler class [" +
					userType.getName() + "]: " + method, ex);
		}
});

selectMethods()
循环判断类上的所有方法,调用方法的匿名内部类中的getMappingForMethod()方法,然后将方法与RequestMappingInfo对象,存到一个map中,并返回

public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
	final Map<Method, T> methodMap = new LinkedHashMap<>();
	Set<Class<?>> handlerTypes = new LinkedHashSet<>();
	Class<?> specificHandlerType = null;

	if (!Proxy.isProxyClass(targetType)) {
		specificHandlerType = ClassUtils.getUserClass(targetType);
		handlerTypes.add(specificHandlerType);
	}
	handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));

	for (Class<?> currentHandlerType : handlerTypes) {
		final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);

		// 循环currentHandlerType类的所有方法
		ReflectionUtils.doWithMethods(currentHandlerType, method -> {
			Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
			// 判断方法上面是否有@RequestMapping注解,如果有封装对象返回
			T result = metadataLookup.inspect(specificMethod);
			if (result != null) {
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
				if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
					// 建立方法对象和注解封装对象的映射关系
					methodMap.put(specificMethod, result);
				}
			}
		}, ReflectionUtils.USER_DECLARED_METHODS);
	}

	return methodMap;
}

getMappingForMethod()

  • 先判断方法是否有@RequestMapping注解,如果没有,遍历下一个方法,如果有,解析注解上的各种值,并用构建成RequestMapping对象(建造者模式)。
  • 在用相同的办法,来解析类上面的注解信息,封装成RequestMapping对象。
  • 然后将类上的RequestMapping与方法上的RequestMapping合并成一个
  • 判断是否有前缀,来决定是否需要在合并后的RequestMapping中,加入该前缀
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
	// 寻找有@RequestMapping注解的方法,然后注解里面的内容封装成对象
	RequestMappingInfo info = createRequestMappingInfo(method);
	if (info != null) {
		// 类上面的@RequestMapping注解也封装成对象
		RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
		if (typeInfo != null) {
			// 把方法上面的注解属性结合到类上面的RequestMappingInfo对象中
			info = typeInfo.combine(info);
		}
		String prefix = getPathPrefix(handlerType);
		if (prefix != null) {
			info = RequestMappingInfo.paths(prefix).build().combine(info);
		}
	}
	return info;
}
  • 建立uri和方法的各种映射关系 (下半部分)
methods.forEach((method, mapping) -> {
	Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
	// 建立uri和方法的各种映射关系,反正一条,根据uri要能够找到method对象
	registerHandlerMethod(handler, invocableMethod, mapping);
});

registerHandlerMethod()

private final MappingRegistry mappingRegistry = new MappingRegistry();

protected void registerHandlerMethod(Object handler, Method method, T mapping) {
	this.mappingRegistry.register(mapping, handler, method);
}

register()

  • 创建HandlerMethod对象,对象中存放的是beanName/bean实例(在调用的时候会实例化),跟对应的method
  • 建立RequestMappingInfo跟handlerMethod映射关系
  • 建立url和RequestMappingInfo的映射关系
public void register(T mapping, Object handler, Method method) {
	this.readWriteLock.writeLock().lock();
	try {
		// 创建HandlerMethod对象
		HandlerMethod handlerMethod = createHandlerMethod(handler, method);
		// 检验是否唯一
		assertUniqueMethodMapping(handlerMethod, mapping);
		// 建立uri对象和handlerMethod的映射关系
		this.mappingLookup.put(mapping, handlerMethod);

		List<String> directUrls = getDirectUrls(mapping);
		for (String url : directUrls) {
			// 建立url和RequestMappingInfo映射关系
			this.urlLookup.add(url, mapping);
		}

		String name = null;
		if (getNamingStrategy() != null) {
			name = getNamingStrategy().getName(handlerMethod, mapping);
			addMappingName(name, handlerMethod);
		}

		// 判断method上是否有CrossOrigin注解,把注解里面的属性封装成CorsConfiguration,这个是做跨域访问控制的
		CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
		if (corsConfig != null) {
			// 建立映射关系
			this.corsLookup.put(handlerMethod, corsConfig);
		}

		this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
	}
	finally {
		this.readWriteLock.writeLock().unlock();
	}
}

到此,就能根据请求的url,找到一个唯一的HandlerMethod对象,但是方法反射调用,需要的是
对象实例,方法跟参数,前两个已经有了,现在只缺参数了

dispatcherServlet处理请求

当请求过来,会先手调用DispatcherServletdoService()方法,会调用到doDispatch()方法,
其中重点的几个方法

getHandler()

获取对应的HandlerExecutionChain 对象

HandlerExecutionChain mappedHandler = null;
// 。。。。。。
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
	noHandlerFound(processedRequest, response);
	return;
}
// ---------- DispatcherServlet 类 --------------

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	// handlerMappering实例
	if (this.handlerMappings != null) {
		for (HandlerMapping mapping : this.handlerMappings) {
			// 获取HandlerMethod和过滤器链的包装类
			HandlerExecutionChain handler = mapping.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
	}
	return null;
}


// ---------- AbstractHandlerMapping 类 ---------------
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	// 根据请求的uri拿到对应的HandlerMethod对象
	Object handler = getHandlerInternal(request);
	if (handler == null) {
		handler = getDefaultHandler();
	}
	if (handler == null) {
		return null;
	}
	// Bean name or resolved handler?
	if (handler instanceof String) {
		String handlerName = (String) handler;
		handler = obtainApplicationContext().getBean(handlerName);
	}

	// 获取HandlerMethod和过滤器链的包装类
	HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

	if (logger.isTraceEnabled()) {
		logger.trace("Mapped to " + handler);
	}
	else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
		logger.debug("Mapped to " + executionChain.getHandler());
	}

	// 是否是跨域请求,就是查看request请求头中是否有Origin属性
	if (CorsUtils.isCorsRequest(request)) {
		// 自定义的钩子方法获取跨域配置
		CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
		// 注解获取跨域配置
		CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
		CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
		// 这里设置了跨域的过滤器CorsInterceptor
		executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
	}

	return executionChain;
}

// -------------getHandlerInternal() 方法,获取HandlerMethod,并把HandlerMethod中的beanName实例化成bean
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
	// 从request对象中获取uri,/common/query2
	String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
	this.mappingRegistry.acquireReadLock();
	try {
		// 根据uri从映射关系中找到对应的HandlerMethod对象
		/*
			1.根据uri,从urlLookup中,获取RquestMappingInfo 对象
			2.根据RequestMappingInfo对象,从mappingLookup中,获取HandlerMethod对象
			3.把ReqestMapingInfo,HandlerMethod对象。封装成Match对象
			4.判断是否有多个匹配的HandlerMethod对象,如果有,判断最佳匹配的。如果没有,直接返回
			5.如果匹配到有两个相同的,直接报错
			6.返回HandlerMethod对象
		*/
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		// 把Controller类实例化
		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
	}
	finally {
		this.mappingRegistry.releaseReadLock();
	}
}

// ---------------getHandlerExecutionChain() 方法,获取HandlerExecutionChain 对象,并判断是否有拦截器,如果有的话。添加进拦截器链中返回
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
	// 把HandlerMethod对象包装到HandlerExecutionChain对象中,这个对象中有过滤器对象
	HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
			(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

	// 获取uri
	String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);

	// 是否有过滤器
	for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
		if (interceptor instanceof MappedInterceptor) {
			MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
			if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
				chain.addInterceptor(mappedInterceptor.getInterceptor());
			}
		}
		else {
			chain.addInterceptor(interceptor);
		}
	}
	return chain;
}

getHandlerAdapter

获取对应的HandlerAdapter

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// -----------------------
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
	// 根据handlerMethod对象,找到合适的HandlerAdapter对象,这里用到了策略模式
	if (this.handlerAdapters != null) {
		for (HandlerAdapter adapter : this.handlerAdapters) {
			if (adapter.supports(handler)) {
				return adapter;
			}
		}
	}
	throw new ServletException("No adapter for handler [" + handler +
			"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

mappedHandler.applyPreHandle

前置处理,调用跟改uri匹配的拦截器的preHandle方法,如果其中一个返回false,则该方法结束调用

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

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
	HandlerInterceptor[] interceptors = getInterceptors();
	if (!ObjectUtils.isEmpty(interceptors)) {
		for (int i = 0; i < interceptors.length; i++) {
			HandlerInterceptor interceptor = interceptors[i];
			if (!interceptor.preHandle(request, response, this.handler)) {
				triggerAfterCompletion(request, response, null);
				return false;
			}
			this.interceptorIndex = i;
		}
	}
	return true;
}

ha.handle

执行controller具体方法,关键点在参数的解析

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

中间代码很多,主要流程
handle()

方法调用

public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
	throws Exception {

	return handleInternal(request, response, (HandlerMethod) handler);
}

–>AbstractHandlerMethodAdapter.handleInternal()

protected ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

	ModelAndView mav;
	checkRequest(request);

	// Execute invokeHandlerMethod in synchronized block if required.
	if (this.synchronizeOnSession) {
		HttpSession session = request.getSession(false);
		if (session != null) {
			Object mutex = WebUtils.getSessionMutex(session);
			synchronized (mutex) {
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
			// No HttpSession available -> no mutex necessary
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}
	}
	else {
		// Controller里面具体方法调用
		// No synchronization on session demanded at all...
		mav = invokeHandlerMethod(request, response, handlerMethod);
	}

	if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
		if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
			applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
		}
		else {
			prepareResponse(response);
		}
	}

	return mav;
}

–>RequestMappingHandlerAdapter.invokeHandlerMethod()
各种解析

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

	ServletWebRequest webRequest = new ServletWebRequest(request, response);
	try {
		// 获取数据绑定工厂  @InitBinder注解支持
		WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
		// Model工厂,收集了@ModelAttribute注解的方法
		ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

		// 可调用的方法对象
		ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
		if (this.argumentResolvers != null) {
			// 设置参数解析器
			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
		}
		if (this.returnValueHandlers != null) {
			// 设置返回值解析器
			invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
		}
		// 设置参数绑定工厂
		invocableMethod.setDataBinderFactory(binderFactory);
		// 设置参数名称解析类
		invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

		ModelAndViewContainer mavContainer = new ModelAndViewContainer();
		mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
		// 调用有@ModelAttribute注解的方法。每次请求都会调用有@ModelAttribute注解的方法
		// 把@ModelAttribute注解的方法的返回值存储到 ModelAndViewContainer对象的map中了
		modelFactory.initModel(webRequest, mavContainer, invocableMethod);
		mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

		AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
		asyncWebRequest.setTimeout(this.asyncRequestTimeout);

		// 异步处理
		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.setTaskExecutor(this.taskExecutor);
		asyncManager.setAsyncWebRequest(asyncWebRequest);
		asyncManager.registerCallableInterceptors(this.callableInterceptors);
		asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

		if (asyncManager.hasConcurrentResult()) {
			Object result = asyncManager.getConcurrentResult();
			mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
			asyncManager.clearConcurrentResult();
			LogFormatUtils.traceDebug(logger, traceOn -> {
				String formatted = LogFormatUtils.formatValue(result, !traceOn);
				return "Resume with async result [" + formatted + "]";
			});
			invocableMethod = invocableMethod.wrapConcurrentResult(result);
		}

		// Controller方法调用
		invocableMethod.invokeAndHandle(webRequest, mavContainer);
		if (asyncManager.isConcurrentHandlingStarted()) {
			return null;
		}

		return getModelAndView(mavContainer, modelFactory, webRequest);
	}
	finally {
		webRequest.requestCompleted();
	}
}

–>RequestMappingHandlerAdapter.invokeAndHandle()
方法调用跟处理返回值

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

	// 具体调用逻辑
	Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
	setResponseStatus(webRequest);

	if (returnValue == null) {
		if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
			mavContainer.setRequestHandled(true);
			return;
		}
	}
	else if (StringUtils.hasText(getResponseStatusReason())) {
		mavContainer.setRequestHandled(true);
		return;
	}

	mavContainer.setRequestHandled(false);
	Assert.state(this.returnValueHandlers != null, "No return value handlers");
	try {
		// 返回值处理
		this.returnValueHandlers.handleReturnValue(
				returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
	}
	catch (Exception ex) {
		if (logger.isTraceEnabled()) {
			logger.trace(formatErrorForReturnValue(returnValue), ex);
		}
		throw ex;
	}
}

–>ServletInvocableHandlerMethod.invokeForRequest()
解析参数跟方法调用

public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
		Object... providedArgs) throws Exception {

	// 获取参数数组
	Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
	if (logger.isTraceEnabled()) {
		logger.trace("Arguments: " + Arrays.toString(args));
	}
	return doInvoke(args);
}

–>InvocableHandlerMethod.getMethodArgumentValues()
解析参数

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

	if (ObjectUtils.isEmpty(getMethodParameters())) {
		return EMPTY_ARGS;
	}
	// 入参的包装类,里面包装了参数类型,参数名称,参数注解等等信息
	MethodParameter[] parameters = getMethodParameters();
	Object[] args = new Object[parameters.length];
	for (int i = 0; i < parameters.length; i++) {
		MethodParameter parameter = parameters[i];
		// 设置参数名称解析器
		parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
		args[i] = findProvidedArgument(parameter, providedArgs);
		if (args[i] != null) {
			continue;
		}
		// 典型的策略模式,根据parameter能否找到对应参数的处理类,能找到就返回true
		if (!this.resolvers.supportsParameter(parameter)) {
			throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
		}
		try {
			// 具体参数值解析过程
			args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
		}
		catch (Exception ex) {
			// Leave stack trace for later, exception may actually be resolved and handled..
			if (logger.isDebugEnabled()) {
				String error = ex.getMessage();
				if (error != null && !error.contains(parameter.getExecutable().toGenericString())) {
					logger.debug(formatArgumentError(parameter, error));
				}
			}
			throw ex;
		}
	}
	return args;
}

// ----------------InvocableHandlerMethod -----------------
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

	// 根据参数获取对应参数的解析类
	HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
	if (resolver == null) {
		throw new IllegalArgumentException(
				"Unsupported parameter type [" + parameter.getParameterType().getName() + "]." +
						" supportsParameter should be called first.");
	}
	// 策略模式去调用具体参数解析类
	return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);

}

–> InvocableHandlerMethod.doInvoke()
方法调用

protected Object doInvoke(Object... args) throws Exception {
	ReflectionUtils.makeAccessible(getBridgedMethod());
	try {
		return getBridgedMethod().invoke(getBean(), args);
	}
	catch (IllegalArgumentException ex) {
		assertTargetBean(getBridgedMethod(), getBean(), args);
		String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
		throw new IllegalStateException(formatInvokeError(text, args), ex);
	}
	catch (InvocationTargetException ex) {
		// Unwrap for HandlerExceptionResolvers ...
		Throwable targetException = ex.getTargetException();
		if (targetException instanceof RuntimeException) {
			throw (RuntimeException) targetException;
		}
		else if (targetException instanceof Error) {
			throw (Error) targetException;
		}
		else if (targetException instanceof Exception) {
			throw (Exception) targetException;
		}
		else {
			throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
		}
	}
}

处理返回值

ServletInvocableHandlerMethod类的invokeAndHandle()中
返回值可能是数据,也可能是跳转的界面

  • 根据返回值,返回值类型,找到一个处理的handler
  • 使用策略模式进行解析
try {
	//返回值处理
	this.returnValueHandlers.handleReturnValue(
				returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
	}
catch (Exception ex) {
	if (logger.isTraceEnabled()) {
		logger.trace(formatErrorForReturnValue(returnValue), ex);
	}
	throw ex;
}
--------------------------------

@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
		ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

	HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
	if (handler == null) {
		throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
	}
	handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}

mappedHandler.applyPostHandle

中置处理

mappedHandler.applyPostHandle(processedRequest, response, mv);

processDispatchResult

视图解析

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);
			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;
	}

	// 后置过滤器
	if (mappedHandler != null) {
		mappedHandler.triggerAfterCompletion(request, response, null);
	}
}

render()

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
	// Determine locale for request and apply it to the response.
	Locale locale =
			(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
	response.setLocale(locale);

	View view;
	String viewName = mv.getViewName();
	if (viewName != null) {
		// We need to resolve the view name.
		view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
		if (view == null) {
			throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
					"' in servlet with name '" + getServletName() + "'");
		}
	}
	else {
		// No need to lookup: the ModelAndView object contains the actual View object.
		view = mv.getView();
		if (view == null) {
			throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
					"View object in servlet with name '" + getServletName() + "'");
		}
	}

	// Delegate to the View object for rendering.
	if (logger.isTraceEnabled()) {
		logger.trace("Rendering view [" + view + "] ");
	}
	try {
		if (mv.getStatus() != null) {
			response.setStatus(mv.getStatus().value());
		}
		// 核心逻辑
		view.render(mv.getModelInternal(), request, response);
	}
	catch (Exception ex) {
		if (logger.isDebugEnabled()) {
			logger.debug("Error rendering view [" + view + "]", ex);
		}
		throw ex;
	}
}

view.render

public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
			HttpServletResponse response) throws Exception {

	if (logger.isDebugEnabled()) {
		logger.debug("View " + formatViewName() +
				", model " + (model != null ? model : Collections.emptyMap()) +
				(this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));
	}

	Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
	prepareResponse(request, response);
	// 这里进行各种响应
	renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!