文章目录

  • onRefresh刷新dispatcherservlet九大组件的主要地方
  • initMultipartResolver 初始化文件上传解析器
  • initLocaleResolver本地化解析
  • getDefaultStrategy方法获取默认配置(缺省策略)
  • initHandlerMappings处理器映射器 保存Url映射关系(重要)
  • springmvc.xml配置的注解扫描
  • HandlerMapping
  • BeanNameUrlHandlerMapping详解
  • RequestMappingHandlerMapping详解(通过@RequestMapping配置的类重要)
  • HandlerAdapter
  • SimpleControllerHandlerAdapter
  • HttpRequestHandlerAdapter同理实现HttpRequestHandler接口的
  • RequestMappingHandlerAdapter(重要)



在讲initWebApplicationContext方法的时候,分为两部分,一部分是创建web端的spring容器,一部分是DispatcherServlet的加载,前面一篇

onRefresh刷新dispatcherservlet九大组件的主要地方

onRefresh在frameworkservlet方法里是空的,在dispatcherservlet里重写了onRefresh方法,我们看dispatcherservlet里面的:

@Override
	protected void onRefresh(ApplicationContext context) {
		//初始化九大组件
		initStrategies(context);
	}

protected void initStrategies(ApplicationContext context) {
		// 初始化文件上传解析器
		initMultipartResolver(context);
		// 本地化解析
		initLocaleResolver(context);
		// 主题解析器
		initThemeResolver(context);
		// 处理器映射器 保存Url映射关系
		initHandlerMappings(context);
		// 处理器适配器
		initHandlerAdapters(context);
		// 异常解析器
		initHandlerExceptionResolvers(context);
		// 视图提取器,从request中获取viemName
		initRequestToViewNameTranslator(context);
		// 视图解析器
		initViewResolvers(context);
		// 参数解析器
		initFlashMapManager(context);
	}

初始这些组件的话,springmvc都有默认的配置,DispatcherServlet.properties;
初始化大体都是先从spring中获取,如果获取不到抛出了NoSuchBeanDefinitionException就走getDefaultStrategies方法从DispatcherServlet.properties中获取配置;大部分代码几乎都是相同的我就简单的讲几个其他都是换汤不换药

initMultipartResolver 初始化文件上传解析器

就是直接从spring容器中取,没取到就设置为空:

private void initMultipartResolver(ApplicationContext context) {
		try {
			this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
			if (logger.isDebugEnabled()) {
				logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
			}
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Default is no multipart resolver.
			this.multipartResolver = null;
			if (logger.isDebugEnabled()) {
				logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
						"': no multipart request handling provided");
			}
		}
	}

initLocaleResolver本地化解析

也是直接从spring容器中取,没取到就从默认配置中获取:

private void initLocaleResolver(ApplicationContext context) {
		try {
			this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
			if (logger.isDebugEnabled()) {
				logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
			}
		}
		catch (NoSuchBeanDefinitionException ex) {
			// We need to use the default.
			this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
			if (logger.isDebugEnabled()) {
				logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
						"': using default [" + this.localeResolver + "]");
			}
		}
	}

getDefaultStrategy方法获取默认配置(缺省策略)

这个方法就是从DispatcherServlet.properties;文件中获取默认配置,代码都很简单,就通过配置,将类通过反射初始化出来而已:

protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface) {
	// 正在获取默认配置的地方
		List<T> strategies = getDefaultStrategies(context, strategyInterface);
		if (strategies.size() != 1) {
			throw new BeanInitializationException(
					"DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]");
		}
		//返回第一个
		return strategies.get(0);
	}

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
		String key = strategyInterface.getName();
		String value = defaultStrategies.getProperty(key);
		if (value != null) {
			String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
			List<T> strategies = new ArrayList<T>(classNames.length);
			for (String className : classNames) {
				try {
				  // 通过反射将类初始化出来
					Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
					Object strategy = createDefaultStrategy(context, clazz);
					strategies.add((T) strategy);
				}
				catch (ClassNotFoundException ex) {
					throw new BeanInitializationException(
							"Could not find DispatcherServlet's default strategy class [" + className +
									"] for interface [" + key + "]", ex);
				}
				catch (LinkageError err) {
					throw new BeanInitializationException(
							"Error loading DispatcherServlet's default strategy class [" + className +
									"] for interface [" + key + "]: problem with class file or dependent class", err);
				}
			}
			return strategies;
		}
		else {
			return new LinkedList<T>();
		}
	}

springmvc源码解析(二),DispatcherServlet加载的过程_解析器

initThemeResolver主题解析器(略同上)

initHandlerMappings处理器映射器 保存Url映射关系(重要)

private void initHandlerMappings(ApplicationContext context) {
	  // 初始化记录 HandlerMapping 对象的属性变量为null
		this.handlerMappings = null;
    // 根据属性detectAllHandlerMappings决定是检测所有的 HandlerMapping 对象,还是
    // 使用指定名称的 HandlerMapping 对象
		if (this.detectAllHandlerMappings) {
			// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
      // 从容器及其祖先容器查找所有类型为 HandlerMapping 的 HandlerMapping 对象,记录到   handlerMappings 并排序
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
				// We keep HandlerMappings in sorted order.
        // 排序,关于这里的排序,可以参考   WebMvcConfigurationSupport 类中对各种 HandlerMapping bean
        // 进行定义时所使用的 order 属性,顺序属性很关键,因为它涉及到 HandlerMapping 使用时的优先级
				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}
		}
		else {
			try {
        // 获取名称为  handlerMapping 的 HandlerMapping bean 并记录到 handlerMappings
        HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
				this.handlerMappings = Collections.singletonList(hm);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerMapping later.
			}
		}

		// Ensure we have at least one HandlerMapping, by registering
		// a default HandlerMapping if no other mappings are found.
    // 如果上面步骤从容器获取 HandlerMapping 失败,则使用缺省策略创建 HandlerMapping 对象记录到handlerMappings
		if (this.handlerMappings == null) {
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isDebugEnabled()) {
				logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
			}
		}
	}

到这里distpatcherservlet的初始化方法大部分都讲完了,这些方法跟上面三个差不多就不做过多描述了:
initHandlerAdapters 处理器适配器(同initHandlerMappings)
initHandlerExceptionResolvers 异常解析器(略)
initRequestToViewNameTranslator 视图提取器,从request中获取viemName(略)
initViewResolvers 视图解析器(略)
initFlashMapManager 参数解析器(略)

springmvc.xml配置的注解扫描

HandlerMapping

在springmvc的配置文件中,通常配置了注解扫描mvc:annotation-driven/,因为前面init是直接从spring容器中直接获取的,在这边配置就能获取到,而解析这个标签的类,里面注册了一些基本的handlermapping,主要有RequestMappingHandlerMapping ,RequestMappingHandlerAdapter ,ExceptionHandlerExceptionResolver ,
BeanNameUrlHandlerMapping
mvc:annotation-driven注解详解

<mvc:annotation-driven/>

BeanNameUrlHandlerMapping详解

首先看类图:

springmvc源码解析(二),DispatcherServlet加载的过程_spring_02


接口ApplicationContextAware是spring包下的,会注入spring容器,各种aware接口,前面讲spring源码的时候说过一次,这里就不做过多描述了;

我们就从ApplicationObjectSupport类的setApplicationContext方法入口看,没啥主要的,看一眼就知道,主要方法是initApplicationContext,然后就是调用AbstractDetectingUrlHandlerMapping的initApplicationContext方法:源码比较简单,主要就是将以/开头的beanName名称跟对应的beanname进行映射,注意是以/开头的bean

所以一般这个类不常用~

@Override
	public void initApplicationContext() throws ApplicationContextException {
		super.initApplicationContext();
		detectHandlers();
	}
	protected void detectHandlers() throws BeansException {
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
		}
		String[] beanNames = (this.detectHandlersInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
				getApplicationContext().getBeanNamesForType(Object.class));

		// Take any bean name that we can determine URLs for.
		for (String beanName : beanNames) {
			String[] urls = determineUrlsForHandler(beanName);
			if (!ObjectUtils.isEmpty(urls)) {
				// URL paths found: Let's consider it a handler.
				registerHandler(urls, beanName);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
				}
			}
		}
	}

springmvc源码解析(二),DispatcherServlet加载的过程_解析器_03

RequestMappingHandlerMapping详解(通过@RequestMapping配置的类重要)

首先看看类图,实现了InitializingBean接口,这个接口在spring容器加载完成的时候会执行afterPropertiesSet方法,而这个类主要入口也是这个方法:

springmvc源码解析(二),DispatcherServlet加载的过程_解析器_04


RequestMappingHandlerMapping的afterPropertiesSet方法:

@Override
	public void afterPropertiesSet() {
		//用来保存RequestMapping注解里面的配置项
		this.config = new RequestMappingInfo.BuilderConfiguration();
		// path解析的类
		this.config.setUrlPathHelper(getUrlPathHelper());
		// path匹配
		this.config.setPathMatcher(getPathMatcher());
		// 前缀处理
		this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
		// 是否开启PatternsRequestCondition中的尾随斜杠 默认true
		this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
		// 是否开启后缀访问,方法上的/hello也会匹配到/hello.json路径 默认false
		this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
		// 设置ProducesRequestCondition需要的内容管理器
		this.config.setContentNegotiationManager(getContentNegotiationManager());

		super.afterPropertiesSet();
	}

然后调用父类的afterPropertiesSet方法,这个方法就调用initHandlerMethods方法:

protected void initHandlerMethods() {
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for request mappings in application context: " + getApplicationContext());
		}
		// detectHandlerMethodsInAncestorContexts为false
		// 获取web容器中所有的beanName,如果为true表示从父容器中也获取,就是springcontext中也获取
		String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
				getApplicationContext().getBeanNamesForType(Object.class));

		//遍历
		for (String beanName : beanNames) {
			// 如果beanName没有以SCOPED_TARGET_NAME_PREFIX = "scopedTarget."起始
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
				Class<?> beanType = null;
				try {
					beanType = getApplicationContext().getType(beanName);
				}
				catch (Throwable ex) {
					// An unresolvable bean type, probably from a lazy bean - let's ignore it.
					if (logger.isDebugEnabled()) {
						logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
					}
				}
				// isHandler判断是否有Controller注解或者RequestMapping注解
				if (beanType != null && isHandler(beanType)) {
					// 加载对应handler所有的handlerMethod方法
					detectHandlerMethods(beanName);
				}
			}
		}
		// handlerMethod加载完成后执行,留给子类去扩展
		handlerMethodsInitialized(getHandlerMethods());
	}

protected void detectHandlerMethods(final Object handler) {
		// 如果 handler为String,则根据beanName获取handlerType否则获取类型
		Class<?> handlerType = (handler instanceof String ?
				getApplicationContext().getType((String) handler) : handler.getClass());
		// 判断如果是cglib代理就返回原始的handler类型
		final Class<?> userType = ClassUtils.getUserClass(handlerType);

		// 返回处理后的requestMappingInfo
		Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				new MethodIntrospector.MetadataLookup<T>() {
					@Override
					public T inspect(Method method) {
						try {
							return getMappingForMethod(method, userType);
						}
						catch (Throwable ex) {
							throw new IllegalStateException("Invalid mapping on handler class [" +
									userType.getName() + "]: " + method, ex);
						}
					}
				});

		if (logger.isDebugEnabled()) {
			logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
		}
		for (Map.Entry<Method, T> entry : methods.entrySet()) {
			Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
			T mapping = entry.getValue();
			// 注解handlerMethod到mappingRegistry
			registerHandlerMethod(handler, invocableMethod, mapping);
		}
	}

中间的处理标签的过程比较复杂~感兴趣可以看看,

springmvc源码解析(二),DispatcherServlet加载的过程_spring_05


最后注册就是将各种信息保存到mappingRegistry里面:

springmvc源码解析(二),DispatcherServlet加载的过程_解析器_06


下篇就讲请求流程,这时候mapping就至关重要了~

HandlerAdapter

适配器在请求的时候,会根据对应的handler获取对应的handler适配器,

由于是遍历handlerAdapter的集合,来查找这个handlerAdapter是否匹配这个Handler,调用的都是HandlerAdapter中的supports方法。

HandlerAdapter的主要几个实现HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter,RequestMappingHandlerAdapter(最重要),:

springmvc源码解析(二),DispatcherServlet加载的过程_初始化_07

SimpleControllerHandlerAdapter

我们看supports方法,就是判断是否是Controller类,对应的控制器实现了Controller类接口就使用这个适配器,然后执行也是执行handler方法,SimpleControllerHandlerAdapter,HttpRequestHandlerAdapter都是直接执行对应handler的handleRequest方法就返回了,比较简单:

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

	@Override
	public boolean supports(Object handler) {
		return (handler instanceof Controller);
	}

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

		return ((Controller) handler).handleRequest(request, response);
	}

	@Override
	public long getLastModified(HttpServletRequest request, Object handler) {
		if (handler instanceof LastModified) {
			return ((LastModified) handler).getLastModified(request);
		}
		return -1L;
	}

}

HttpRequestHandlerAdapter同理实现HttpRequestHandler接口的

public class HttpRequestHandlerAdapter implements HandlerAdapter {

	@Override
	public boolean supports(Object handler) {
		return (handler instanceof HttpRequestHandler);
	}

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

		((HttpRequestHandler) handler).handleRequest(request, response);
		return null;
	}

	@Override
	public long getLastModified(HttpServletRequest request, Object handler) {
		if (handler instanceof LastModified) {
			return ((LastModified) handler).getLastModified(request);
		}
		return -1L;
	}

}

RequestMappingHandlerAdapter(重要)

这个类没有判断,是根据父类去判断的,父类判断是否是HandlerMethod类,然后执行子类的supportsInternal,这个方法直接返回true,可以自己去实现AbstractHandlerMethodAdapter然后自己定义规则适配,

springmvc源码解析(二),DispatcherServlet加载的过程_解析器_08


我们看这个类的初始化方法,实现了InitializingBean,就看afterPropertiesSet方法:

@Override
	public void afterPropertiesSet() {
		// Do this first, it may add ResponseBody advice beans
		//初始化ControllerAdvice注解需要的东西
		initControllerAdviceCache();

		//获取参数解析器
		if (this.argumentResolvers == null) {
			List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
			this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
		//获取桥接方法的参数
		if (this.initBinderArgumentResolvers == null) {
			List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
			this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
		//返回参数参数解析
		if (this.returnValueHandlers == null) {
			List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
			this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
		}
	}

初始化了一些组件,像参数解析器,返回参数解析器等等,在对请求进行解析的时候至关重要.