目录
1、RequestMappingHandlerMapping结构
4)、将RequestMapping注解修饰的方法以RequestMappingInfo返回
二、doDispatch的getHandlerAdapter
1、RequestMappingHandlerAdapter
4、SimpleControllerHandlerAdapter
一、doDispatch的getHandler
SpringMVC中比较重要的就是doDispatch,而其中第一个比较重要的就是根据HttpServletRequest(当前为RequestFacade类型)获取HandlerExecutionChain(调用的Controller和需要调用的HandlerInterceptor链)。
@Nullable
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;
}
遍历所有的加载HandlerMapping子类列表,调用HandlerMapping定义的getHandler方法,如果不为null则适配成功。现在主要使用@RequestMapping形式的对应的HandlerMapping为RequestMappingHandlerMapping类型。
1、RequestMappingHandlerMapping结构
1、实现了ApplicationContextAware接口,回调setApplicationContext方法时。赋值ApplicationContext给后面的afterPropertiesSet回调,从BeanFactory中获取Object类型的所有Bean做准备;并且完成了所有HandlerInteceptor的初始化。
2、实现了InitializingBean,并且在getBean时的afterPropertiesSet回调中完成了请求调用前的准备工作。将Bean 中的@RequestMapping解析为RequestMappingInfo。
3、实现了HandlerMapping接口,请求调用时getHandler获取到匹配的具体调用方法和拦截器执行链
2、setApplicationContext回调函数
@Override
public final void setApplicationContext(@Nullable ApplicationContext context)
throws BeansException {
// 省略
} else if (this.applicationContext == null) {
// Initialize with passed-in context.
if (!requiredContextClass().isInstance(context)) {
throw new ApplicationContextException("省略");
}
this.applicationContext = context;
this.messageSourceAccessor = new MessageSourceAccessor(context);
initApplicationContext(context);
} // 省略
}
主要会对ApplicationContext进行赋值;初始化MessageSourceAccessor对象;并且调用自定义的初始化方法。
protected void initApplicationContext(ApplicationContext context) throws BeansException {
initApplicationContext();
}
@Override
protected void initApplicationContext() throws BeansException {
extendInterceptors(this.interceptors);
detectMappedInterceptors(this.adaptedInterceptors);
initInterceptors();
}
全是对HandlerIntecepter的处理:
1)、extendInterceptors为空方法,子类没有实现
2)、将BeanFactory中所有MappedInterceptor类型的Bean加载进来
protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
mappedInterceptors.addAll(
BeanFactoryUtils.beansOfTypeIncludingAncestors(
obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}
3)、其他地方都是调用方法将HandlerInteceptor加入到interceptors集合中,现在是将里面的所以对象都适配到adaptedInterceptors中,方法调用时在该集合中匹配处理。
protected void initInterceptors() {
if (!this.interceptors.isEmpty()) {
for (int i = 0; i < this.interceptors.size(); i++) {
Object interceptor = this.interceptors.get(i);
if (interceptor == null) {
throw new IllegalArgumentException("省略");
}
this.adaptedInterceptors.add(adaptInterceptor(interceptor));
}
}
}
适配方法adaptInterceptor如下:
protected HandlerInterceptor adaptInterceptor(Object interceptor) {
if (interceptor instanceof HandlerInterceptor) {
return (HandlerInterceptor) interceptor;
} else if (interceptor instanceof WebRequestInterceptor) {
return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);
} else {
throw new IllegalArgumentException("省略");
}
}
3、afterPropertiesSet回调函数
@Override
public void afterPropertiesSet() {
this.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();
}
完成配置的初始化(后续getHandler是需要的工具)后,就调用父类的afterPropertiesSet方法。
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
protected void initHandlerMethods() {
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
1)、拿到所有可能被会有调用方法的类
2)、获取注解方法,并注册到mappingRegistry中
3)、日志打印解析的handlerMethods的总数
1)、获取可能的类
protected String[] getCandidateBeanNames() {
return (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
obtainApplicationContext().getBeanNamesForType(Object.class));
}
该参数默认为false,基本都会调用后面的逻辑。获取BeanFactory中所有Object类型的Bean(差不多又是暴力的获取全部)。
2)、解析和注册
protected void processCandidateBean(String beanName) {
// 省略try catch代码
Class<?> beanType = obtainApplicationContext().getType(beanName);
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
从BeanFactory中获取对应的Bean,在调用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 catch的代码
return getMappingForMethod(method, userType);
});
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
1、先获取对应的Class
2、根据Class先获取真实的Class(cglib中包含$$字符);再递归(递归时可能有代理,也要获取真实的Class)获取所有的方法;再判断是否存在@RequestMap注解,则创建RequestMappingInfo对象,返回Method与RequestMappingInfo的Map键值对。
3、注册HandlerMethod
3)、递归查询所有的方法
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;
}
4)、将RequestMapping注解修饰的方法以RequestMappingInfo返回
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);
}
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).build().combine(info);
}
}
return info;
}
先根据Method调用创建,再用Class调用创建,并调用combine方法设置到父RequestMappingInfo。
@Nullable
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对象。
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();
}
5)、注册调用方法
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
如果方法是被代理的,则获取真实的方法。再进行注册:
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
public void register(T mapping, Object handler, Method method) {
// Assert that the handler method is not a suspending one.
if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
}
this.readWriteLock.writeLock().lock();
try {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
validateMethodMapping(handlerMethod, mapping);
this.mappingLookup.put(mapping, 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();
}
}
1、打开写锁(getHandler进行匹配时,使用读锁)
2、创建HandlerMethod对象(就是我们@RequestMapping注解的字符串和Method)
new HandlerMethod(handler, method)
3、mappingLookup添加注册数据(RequestMappingInfo 和 HandlerMethod的关系)
// mapping为之前创建的 RequestMappingInfo 对象
this.mappingLookup.put(mapping, handlerMethod);
4、urlLookup添加注册数据(@RequestMapping类将的加上方法上的字符串和)
// url为@RequestMapping类上加上方法上的字符串;mapping为当前Bean的名称
this.urlLookup.add(url, mapping);
5、获取策略,拼装该方法的请求url
String name = null;
// 策略为RequestMappingInfoHandlerMethodMappingNamingStrategy
if (getNamingStrategy() != null) {
// 获取策略名称
name = getNamingStrategy().getName(handlerMethod, mapping);
// 注册到nameLookup容器中
addMappingName(name, handlerMethod);
}
根据策略RequestMappingInfoHandlerMethodMappingNamingStrategy调用getName方法,比如:
类上的注解为:@RequestMapping("threadDemoController")
方法上注解为:@GetMapping("threadDemo")
当前名称为:TDC#getUser
拼装规则为: 类上的注解字符串的每个字母的大写 + # + 当前方法名称
再添加到nameLookup容器中(如果之前的List中有数据则,添加完之后为原数据 + 现有数据)。
6、处理cors跨域(后续再分析)
7、注册MappingRegistration类型的对象,key为之前创建的RequestMappingInfo对象。
二、doDispatch的getHandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("省略");
}
遍历所有注入的HandlerAdapter,调用support进行判断,不同类型实现不同。 得到适配器之后,主要的是调用handler方法进行具体方法的调用处理,单主要是通过解析后handler的类型进行判断,可以参考SpringMVC源码(四)- 常用HandlerMapping和HandlerAdaptor组合和使用方式
1、RequestMappingHandlerAdapter
@Override
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
如果是使用@RequestMapping解析后得到的为HandlerMethod类型,所以直接进行判断。并且调用supportsInternal方法:
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
2、HandlerFunctionAdapter
@Override
public boolean supports(Object handler) {
return handler instanceof HandlerFunction;
}
3、HttpRequestHandlerAdapter
@Override
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}
直接判断解析后的handler,是否是实现了接口HttpRequestHandler。
4、SimpleControllerHandlerAdapter
@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
同样直接判断是否实现了Controller接口。
5、SimpleServletHandlerAdapter
@Override
public boolean supports(Object handler) {
return (handler instanceof Servlet);
}
同样直接判断是否实现了Servlet接口,其HttpServlet的顶层父类包含Servlet。
三、总结
前提:SpringMVC在初始化DispatcherServlet的init方法时,间接的将九大件初始化,其中就包括了HandlerMapping中的RequestMappingHandlerMapping类型。
1、setApplicationContext回调方法中,初始化完成了所有的HandlerInteceptor
2、afterPropertiesSet回调方法中,从BeanFactory中获取到所有的Bean。遍历所有的类,再递归遍历所有的父类,将有@RequestMapping的方法创建为RequestMappingInfo类型,注册到时又先创建HandlerMethod对象,再以MappingRegistration的形式注册到内部属性mappingRegistry中(key为RequestMappingInfo,value为MappingRegistration)。
3、当方法调用(getHandler)时,将HTTPServletRequest解析适配对应的HandlerMethod和需要执行的拦截器调用链(下一篇继续解析)。
3)、一切准备就绪,待RequestMappingHandlerAdapter的适配,调用具体的方法。