前言
我們已經(jīng)知道HandlerMapping的主要作用是通過request找到Handler,Spring MVC中HandlerMapping的實(shí)現(xiàn)有很多,比如SimpleUrlHandlerMapping曙博、BeanNameUrlHandlerMapping果善、DefaultAnnotationHandlerMapping以及RequestMappingHandlerMapping等等,本篇文章就來分析下最常用的RequestMappingHandlerMapping窟社。
RequestMappingHandlerMapping
我們先來看下RequestMappingHandlerMapping的繼承關(guān)系序苏,然后從繼承關(guān)系從上到下依次分析振惰。
HandlerMapping
HandlerMapping我們已經(jīng)分析過了绿饵,不過最好還是回顧下接口的定義
public interface HandlerMapping {
String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";
String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";
String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";
String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables";
String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
AbstractHandlerMapping
創(chuàng)建過程
AbstractHandlerMapping繼承了WebApplicationObjectSupport欠肾,初始化的時候會調(diào)用initApplicationContext,其內(nèi)部主要是初始化interceptors拟赊,供以后使用刺桃。
Interceptor分為兩種
- 一種是直接或間接實(shí)現(xiàn)了Interceptor接口的普通攔截器,它對所有的請求都會攔截
- 另一種是MappedInterceptor吸祟,MappedInterceptor內(nèi)部包含一個第一種的攔截器虏肾,但是它有一個matches方法,只有符合要求的請求它才會攔截
protected void initApplicationContext() throws BeansException {
// 模板方法欢搜,用于子類擴(kuò)展或修改interceptors封豪,不過并沒有子類實(shí)現(xiàn)
extendInterceptors(this.interceptors);
// 將ApplicationContext中所有的MappedInterceptor添加到adaptedInterceptors中
detectMappedInterceptors(this.adaptedInterceptors);
// 將interceptors中的元素添加到adaptedInterceptors中
initInterceptors();
}
使用過程
AbstractHandlerMapping實(shí)現(xiàn)了getHandler方法,主要分為兩個部分
- 獲取Handler炒瘟,這部分是模板方法吹埠,由子類實(shí)現(xiàn)
- 將創(chuàng)建過程中初始化的interceptors和第一步獲取的handler一起組成HandlerExecutionChain
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 模板方法,由子類實(shí)現(xiàn)
Object handler = getHandlerInternal(request);
if (handler == null) {
// 獲取默認(rèn)Handler疮装,默認(rèn)為null
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// handler是beanName缘琅,就從ApplicationContext中取出對應(yīng)的bean
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
// 通過handler和request獲取HandlerExecutionChain
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
// 如果是cors請求,添加一些攔截器
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
現(xiàn)在我們再來看下獲取HandlerExecutionChain的具體過程廓推,第一步是構(gòu)造HandlerExecutionChain刷袍,第二步是根據(jù)情況添加攔截器。
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 構(gòu)造HandlerExecutionChain
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// 添加攔截器
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
// 添加符合條件的MappedInterceptor
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
} else {
// 非MappedInterceptor都添加進(jìn)來
chain.addInterceptor(interceptor);
}
}
return chain;
}
AbstractHandlerMethodMapping
我們先來解釋下AbstractHandlerMethodMapping中泛型T的含義樊展,官方定義為The mapping for a HandlerMethod containing the conditions needed to match the handler method to incoming request
呻纹,也就是它是一個包含了各種條件(包括url、HttpMethod专缠、Header等)的一個類雷酪,通過這個類可以找到一個HandlerMethod(一種Handler),T默認(rèn)的實(shí)現(xiàn)是RequestMappingInfo涝婉。
創(chuàng)建過程
AbstractHandlerMethodMapping實(shí)現(xiàn)了InitializingBean哥力,所以它的初始化入口是
afterPropertiesSet,其內(nèi)部只是簡單地調(diào)用了initHandlerMethods方法墩弯,并沒有做其他操作吩跋,下面我們來看下initHandlerMethods的具體實(shí)現(xiàn)
protected void initHandlerMethods() {
// 找到ApplicationContext中所有的beanName
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
// 獲取到bean
beanType = getApplicationContext().getType(beanName);
}
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
// isHandler是模板方法
if (beanType != null && isHandler(beanType)) {
// 將bean中符合條件的方法注冊到mappingRegistry
detectHandlerMethods(beanName);
}
}
}
// 對handler做一些初始化操作,模板方法渔工,并沒有子類實(shí)現(xiàn)
handlerMethodsInitialized(getHandlerMethods());
}
這里說一下isHandler方法锌钮,它由RequestMappingHandlerMapping實(shí)現(xiàn),可以看出它的判斷依據(jù)是類上是否有@Controller或@RequestMapping注解涨缚。
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
下面我們再來具體看下detectHandlerMethods方法
protected void detectHandlerMethods(final Object handler) {
// 獲取handler的類
Class<?> handlerType = (handler instanceof String ?
getApplicationContext().getType((String) handler) : handler.getClass());
// 如果是cglib代理的子類轧粟,則返回父類策治,否則直接返回傳入的類
final Class<?> userType = ClassUtils.getUserClass(handlerType);
// 獲取所有符合條件的方法以及對應(yīng)的匹配條件
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
@Override
public T inspect(Method method) {
try {
// 模板方法,返回方法對應(yīng)的匹配條件
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
}
});
// 注冊到mappingRegistry
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
其實(shí)我們可以總結(jié)出AbstractHandlerMethodMapping的創(chuàng)建過程其實(shí)就是根據(jù)代碼里@Controller和@RequestMapping注解兰吟,將符合條件的方法包裝成HandlerMethod通惫,并且建立HandlerMethod和T的對應(yīng)關(guān)系。
AbstractHandlerMethodMapping的使用過程
從AbstractHandlerMapping的使用過程我們知道混蔼,AbstractHandlerMethodMapping使用的入口是getHandlerInternal方法
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 獲取lookupPath履腋,可以簡單理解成url
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
this.mappingRegistry.acquireReadLock();
try {
// 通過lookupPath和request中的一些條件(比如是GET請求還是POST請求等)找到HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}