前言
上篇文章我们聊了springMVC源码的前两个流程,本篇文章将继续阅读剩下的4个流程。
- 处理器映射器RequestMappingHandlerMapping的初始化流程
- 处理器映射器RequestMappingHandlerMapping查找对应的处理器的流程
- 处理器适配器RequestMappingHandlerAdapter初始化流程
- 处理器适配器RequestMappingHandlerAdapter的执行流程
处理器映射器RequestMappingHandlerMapping的初始化流程
首先说下RequestMappingHandlerMapping处理器映射器主要是根据@RequestMapping注解来查找处理器,接着我们来看下RequestMappingHandlerMapping的继承体系
我们看到RequestMappingHandlerMapping继承了InitializingBean,因此,该类肯定实现了afterPropertiesSet方法,在bean创建完成之后进行一些初始化操作,这里就是我们阅读源码的入口。接着我们看下这个方法
his.config = new RequestMappingInfo.BuilderConfiguration();
this.config.setUrlPathHelper(getUrlPathHelper());
this.config.setPathMatcher(getPathMatcher());
this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
this.config.setContentNegotiationManager(getContentNegotiationManager());
super.afterPropertiesSet();
这里主要是设置一些信息,并没有处理主流程的逻辑,因此我们往父类找,可以找到AbstractHandlerMethodMapping的initHandlerMethods方法,就是查找处理器的主流程
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
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.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
- 首先获取容器中的所有beanName
- 接着通过beanName得到对于的class类型
- 判断该类是否是一个Handler类,是的话就进入处理流程,也就是进入detectHandlerMethods方法,那么怎么判断是否是一个Handler类呢,在这边其实我们都知道是通过注解判断的,我们可以直接看下isHandler方法就很清楚了
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
很明显,这里就是判断如果该类上有@Controller或者@RequestMapping的注解那么该类就是我们要找的处理器。 接着我们看下detectHandlerMethods方法
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
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);
}
});
if (logger.isDebugEnabled()) {
logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
}
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
- 获取处理器的class对象不为null就继续
- 这里有个函数式编程,我们先来看下这个方法getMappingForMethod返回的是什么东西
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
info = typeInfo.combine(info);
}
}
return info;
}
从这里我们可以看到该方法主要是创建了一个RequestMappingInfo对象,接着我们看下创建这个对象封装 了哪些信息,我们进入createRequestMappingInfo方法
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
RequestCondition<?> condition = (element instanceof Class ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
这里我们找到方法上的RequestMapping注解,如果注解不为空,就创建一个RequestMappingInfo对象,我们看下这个createRequestMappingInfo的重载方法
protected RequestMappingInfo createRequestMappingInfo(
RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {
RequestMappingInfo.Builder builder = RequestMappingInfo
.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
.methods(requestMapping.method())
.params(requestMapping.params())
.headers(requestMapping.headers())
.consumes(requestMapping.consumes())
.produces(requestMapping.produces())
.mappingName(requestMapping.name());
if (customCondition != null) {
builder.customCondition(customCondition);
}
return builder.options(this.config).build();
}
从这里我们就明白了,这边通过建造者将RequestMapping注解中的信息封装到RequestMappingInfo对象中。最终,我们知道getMappingForMethod方法就是将方法上和类上的RequestMapping注解信息封装到RequestMappingInfo对象中,并返回,接着我们就看下MethodIntrospector的selectMethods做了什么事情
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);
ReflectionUtils.doWithMethods(currentHandlerType, method -> {
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
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;
}
这段代码主要就是执行以下流程,查找对于Handler类中的所有符合的方法,并将该方法和封装RequestMapping信息的RequestMappingInfo类建立映射关系,并返回。 接着就是调用registerHandlerMethod方法,对映射关系进行处理,这个就是初始化流程的最后一步
public void register(T mapping, Object handler, Method method) {
this.readWriteLock.writeLock().lock();
try {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);
this.mappingLookup.put(mapping, handlerMethod);
if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
}
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
this.urlLookup.add(url, mapping);
}
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
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();
}
}
- 将处理器类和对应的方法封装成HandlerMethod对象,其实这个才是真正的处理器,最后是通过反射区调用该方法,因此需要对象和方法信息。
- 确认该方法在映射的map中是唯一的否则就抛出异常
- 将RequestMappingInfo和处理器HandlerMethod的映射关系添加到mappingLookup(存放requestMappingInfo和handlerMethod的映射)
- 获取RequestMapping的url两者添加到urlLookup这个map集合中(urlLookup:存储url和requestMappingInfo的映射关系),一个url可以对应多个RequestMappingInfo(restful中就经常会出现这种情况) 至此,RequestMappingHandlerMapping的初始化流程就完成了。接下去,我们来看,RequestMappingHandlerMapping的处理流程,也就是通过处理器映射器找到对应的处理器,其实在这里就是找到对应的HandlerMethod。
处理器映射器RequestMappingHandlerMapping查找对应的处理器的流程
我们都知道请求来的时候我们需要去获取处理器,因此查找处理器的入口就是在我们前面讲的DispatcherServlet处理请求的方法里面,这里我们就不重复说明,直接说就是DispatcherServlet的getHandler这个方法。
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
这里遍历所有的HandlerMapping,直到有一个HandlerMapping找到处理器就返回结果。 接着玩下跟,找到了AbstractHandlerMapping的getHandler方法
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
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);
}
//形成执行链
。。。
return executionChain;
}
这里面的getHandlerInternal方法又是一个抽象类,其实就是调用子类不同的处理器映射器获取不同的处理器对象,我们是要获取HandlerMethod这个处理器,因此,我们进入他的子类AbstractHandlerMethodMapping类的getHandlerInternal方法,查看获取处理器的具体过程
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//获取请求url
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
this.mappingRegistry.acquireReadLock();
try {
//根据请求url和请求信息获取到对应的处理器handlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
- 通过请求获取到对应的url
- 调用lookupHandlerMethod获取到处理器 接着我们看lookupHandlerMethod方法的具体内容
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
}
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
}
}
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
- 首先根据请求url从我们之前封装的urlLookup(封装RequestMappingInfo和url的映射关系)获取到对应的requestMappingInfo列表
- 通过addMatchingMappings获取到对应Match对象(封装mappinginfo和处理器handlerMethod的对象) 接着我们看下addMatchingMappings的具体内容
for (T mapping : mappings) {
T match = getMatchingMapping(mapping, request);
if (match != null) {
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
找到匹配的requestInfo通过之前封装的mappingLookup获取到对应的处理器封装Match对象中。 具体怎么匹配的有兴趣可以看下getMatchingCondition方法的内容,这里就不再贴出来了。 大致就通过requet中的各种信息去判断是否一致,一致的话就把这些信息创建成一个新的RequestMappinginfo对象和处理器一起封装到match中返回。
最后会把所有匹配到的match进行一个根据匹配度排序(正常只有一个),排序之后获取匹配度最高的一个match对象获取里面的处理器handlerMethod返回,如果排序完之后有多个就会抛出异常。
至此,我们就阅读完了处理器映射器查找处理器对象的一个过程。
处理器适配器RequestMappingHandlerAdapter初始化流程
首先,在这里springMVC使用了适配器模式,但我们这边不会对适配器模式进行详解,因此,如果想要了解设计模式的同学可以去看下其他的博客,会有更详细的介绍。 接着RequestMappingHandlerAdapter实现了InitializingBean,因此,我们知道该类的初始化流程就在afterProperties方法里面,我们接着看下这个方法
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
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);
}
}
这里面主要初始化了什么东西呢
- initControllerAdviceCache注册了处理器增强类的相关操作(@ModelAttribute、@InitBinder、
@ExceptionHandler)也就是这三个注解。
- @ModelAttribute:把值绑定到Model中,使全局@RequestMapping可以获取到该值
- @InitBinder:应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器
- @ExceptionHandler:全局异常捕捉处理
- 接着就是初始化参数解析器,自定义参数解析器,返回值处理器,这些东西会在后面执行Handler方法,也就是真正处理请求的时候调用。 处理器适配器的初始化流程到这边就基本完成了,至于这里面详细的初始化流程我觉得不是我们这边的主干分支,就不深入去看了,有兴趣的同学可以进行再进去详细阅读。
处理器适配器RequestMappingHandlerAdapter的执行流程
RequestMappingHandlerAdapter的处理请求的入口,我想看过前面文章的同学应该就很清楚了,就是DispatcherServlet类的doDispatcher方法中调用对应处理器映射器的handler方法,也就是RequestMappingHandlerAdapter的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 {
// 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;
}
这里我们可以看到实际是调用了invokeHandlerMethod方法去执行,接着往下看
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
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));
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();
if (logger.isDebugEnabled()) {
logger.debug("Found concurrent result value [" + result + "]");
}
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
这里就是创建了一个执行对象invocableMethod,把执行需要的信息都封装进去,例如处理器,方法参数处理器,返回值处理器。最终调用这个对象的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(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
这里调用了invokeForRequest方法去处理请求,我们跟进去看下
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//获取执行参数,参数绑定流程的入口
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(this.getMethod(), this.getBeanType()) + "' with arguments " + Arrays.toString(args));
}
//执行请求
Object returnValue = this.doInvoke(args);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Method [" + ClassUtils.getQualifiedMethodName(this.getMethod(), this.getBeanType()) + "] returned [" + returnValue + "]");
}
return returnValue;
}
最终我们找到找到了具体的执行方法doInvoke
。。
return this.getBridgedMethod().invoke(this.getBean(), args);
。。
在这里我们就清晰地看到了,最终是通过反射去调用了具体的执行方法。也就是我们@Controller类里面的方法。
至此,整个处理器适配器的执行流程就全部看完了。流程没有很复杂,就是一步一步地往下去处理。 同时,这里面有两个稍微重要一点的分支我们这里因为篇幅原因,就不在本篇文章中继续扩展,我这边会说明这两个分支的入口,大家有兴趣可以自己去看下。
- 参数绑定流程,入口就是上面的invokeForRequest里面调用的getMethodArgumentValues方法,里面根据类型的不同主要分为两种,简单类型和POJO类型使用不同的类进行解析,然后根据参数类型的不同也会用不同的解析器进行解析处理。
- 返回值处理流程:入口就是invokeAndHandle里面调用的invokeAndHandle进行处理,因为现在基本上都是通过json返回,一般都加上@ResponseBody注解,加了注解的话会有一个专门的类RequestResponseBodyMethodProcessor去处理,就是讲返回值通过MappingJson的API转出json字符串后,写出。
结语
到这里springMVC的整个流程我们就阅读完毕了,因为篇幅比较长也很开心大家能够耐心的看完这篇文章,springMVC的流程虽然看起来比较清晰但是他里面的细节和一些设计模式都是值得我们去深入学习和了解的。最后,我们SSM源码阅读系列到这里也全部结束了,接下去应该会跟大家一起去聊下mysql的相关内容,希望大家继续支持。