SpringMVC源碼解析之Servlet
SpringMVC源碼解析之GenericServlet和HttpServlet
SpringMVC源碼解析之DispatcherServlet:生命週期init()和destroy()
SpringMVC源碼解析之DispatcherServlet:請求處理
一、HandlerMapping
1. 簡介
前面的博客已經提到,HandlerMapping是SpringMVC的策略組件之一,稱作處理器映射器,其作用是根據請求獲取到對應的處理器。
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
HandlerMapping接口只定義了一個方法,即根據請求獲取到對應的處理器。
2. HandlerMapping的類繼承關係
SpringMVC提供了不少的多層次的HandlerMapping的實現類,RequestMappingHandlerMapping根據註解RequestMapping進行處理器和請求的匹配,是我們日常開發中最常使用的方式,本文也只關注HandlerMapping到RequestMappingHandlerMapping的鏈路上的接口和類的實現。
3. RequestMappingHandlerMapping類圖
二、initApplicationContext方法的解析
AbstractHandlerMapping繼承了WebApplicationObjectSupport接口,通過initApplicationContext方法進行上下文的初始化。
1. 介紹
protected void initApplicationContext() throws BeansException {
//空的模板方法,可以對interceptors進行管理和操作
extendInterceptors(this.interceptors);
//偵測容器中的MappedInterceptor
detectMappedInterceptors(this.adaptedInterceptors);
initInterceptors();
}
initApplicationContext方法子這裏的主要作用是初始化攔截器,在AbstractHandlerMapping中有兩個與攔截器相關的屬性,分別是:
interceptors:
SpringMVC中配置的攔截器集合,可以在註冊HandlerMapping時通過屬性進行設置,也可以在子類中通過重寫模板方法extendInterceptors對interceptors進行
adaptedInterceptors:
(1)在detectMappedInterceptors方法中將Spring容器中的MappedInterceptor類型的bean對象加入搭配adaptedInterceptors
(2)在initInterceptors方法中將interceptors中的對象加入到adaptedInterceptors。(對於HandlerInterceptor類型的Interceptor直接加入,WebRequestInterceptor類型的封裝成WebaRequestHandlerInterceptorAdapter加入,其它類型拋出異常)
adaptedInterceptors中的Interceptor是HandlerInterceptor類型,其子類MappedInterceptor類型的攔截器只對匹配的url的請求有效,其它類型的對所有請求有效。在SpringMVC4中,將MappedInterceptor保存在mappedInterceptors中,其它類型的保存在adaptedInterceptors中,SpringMVC5中還依舊保留着getMappedInterceptors等一些相關的方法。
initApplicationContext方法的調用鏈如下圖所示
2.AbstractHandlerMapping#extendInterceptors(List<Object>)
protected void extendInterceptors(List<Object> interceptors) {
}
該方法是一個空的模板方法,子類可以重寫該方法以實現對interceptors屬性的修改(包括添加和刪除)。
在SpringMVC中,沒有子類對該方法進行了重寫。
3.AbstractHandlerMapping#detectMappedInterceptors(List<HandlerInterceptor>)
protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
mappedInterceptors.addAll(
BeanFactoryUtils.beansOfTypeIncludingAncestors(
obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}
該方法用於檢測Spring容器中的MappedInterceptor類型的bean並加入到集合中。
4. AbstractHandlerMapping#initInterceptors()
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("Entry number " + i + " in interceptors array is null");
}
this.adaptedInterceptors.add(adaptInterceptor(interceptor));
}
}
}
將interceptors中的對象加入中adaptedInterceptors中。
5. AbstractHandlerMapping#adaptInterceptor(Object)
protected HandlerInterceptor adaptInterceptor(Object interceptor) {
//HandlerInterceptor類型不處理
if (interceptor instanceof HandlerInterceptor) {
return (HandlerInterceptor) interceptor;
}
//WebRequestInterceptor類型封裝成適配器WebRequestHandlerInterceptorAdapater
else if (interceptor instanceof WebRequestInterceptor) {
return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);
}
//其它類型拋出異常
else {
throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName());
}
}
該方法將對象封裝成HandlerInterceptor類型。
三、afterProperties的解析
AbstractHandlerMethodMapping實現了InitializaingBean接口,通過afterProperties方法進行初始化。
AbstractHandlerMethodMapping是一個泛型抽象類,從類名上可以看出其是對方法類型的處理器的抽象基本,泛型T可以簡單理解成匹配條件的封裝類,用來表示處理器使用的請求類型。
1. AbstractHandlerMethodMapping
/**
* Detects handler methods at initialization.
*/
//初始化,檢測可以作爲處理器的方法
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
1.1 initHandlerMethod
//掃描容器裏的beans,檢測並註冊處理器方法
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
//獲取容器內的bean集合,detectHandlerMethodsInAncestorContexts是否需要檢查祖先容器,默認false
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);
}
}
//抽象方法isHandler方法判斷是否匹配
if (beanType != null && isHandler(beanType)) {
//從bean中檢測處理器方法
detectHandlerMethods(beanName);
}
}
}
//空的模板方法,進行HandlerMethod的初始化
handlerMethodsInitialized(getHandlerMethods());
}
該方法用於檢測獲取容器中的處理器並進行初始化。
(1)獲取容器中的bean集合
(2)遍歷bean集合,判斷bean的類型是否匹配。如果匹配,從bean中檢測匹配的方法作爲處理器
(3)對處理器進行初始化
1.2 detectHandlerMethods
//找到handler中的方法作爲處理器
protected void detectHandlerMethods(final Object handler) {
//確定類型
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
//返回user-defined的類型,主要是從代理類型到實際類型
final Class<?> userType = ClassUtils.getUserClass(handlerType);
//找到類中方法和匹配條件的映射關係
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
//抽象方法getMappingForMethod
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()) {
//獲取在AOP中對應的方法,方法本身或對應的在接口上的或代理類上的方法
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
//註冊HandlerMethod
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
}
detectHandlerMethods的作用是找到handler對象中的方法作爲處理器。
(1)找到類中可以作爲處理器的方法並獲取匹配條件T組成映射集Map<Method, T>
(2)遍歷映射集,將方法和匹配條件T進行註冊。
1.3 registerHandlerMethod
//對於HanlderMethod的管理由MappingRegistry負責
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
1.4 MappingRegistry
MappingRegistry是AbstractHandlerMapping的內部類,負責對匹配條件集T進行註冊及管理,內部維護着一系列的映射集map和一個讀寫鎖。
//匹配條件T和MappingRegistration的映射關係
private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
//匹配條件T與執行器HanlderMethod的映射關係
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
//url與匹配條件集合的映射關係,一個url可以對應多個匹配條件
private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
//name與執行器集合的映射關係,一個name可以對應多個執行器,name由HandlerMethodMappingNamingStrategy確定,一般由類名和方法名組成
private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
//執行器HandlerMethod與跨域配置CorsConfiguration的映射關係
private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
//讀寫鎖
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
對於Registration,同樣也是AbstractHandlerMethodMapping的一個內部類,由匹配條件T及名稱,處理器和匹配的url而成:
//匹配條件
private final T mapping;
//處理器
private final HandlerMethod handlerMethod;
//url集合
private final List<String> directUrls;
//名稱
@Nullable
private final String mappingName;
MappingRegistry的核心方法就是註冊方法regsiter。
//MappingRegistry#registry
public void register(T mapping, Object handler, Method method) {
//讀寫鎖加寫鎖
this.readWriteLock.writeLock().lock();
try {
//新建HandlerMethod對象
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
//校驗唯一性,一個mapping最多隻能對應一個HandlerMethod
assertUniqueMethodMapping(handlerMethod, mapping);
if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
}
//加入mappingLookup
this.mappingLookup.put(mapping, handlerMethod);
//加入urlLookup
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
this.urlLookup.add(url, mapping);
}
//加入nameLookup
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
//加入corsLookup
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
//加入registry
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
對於匹配名稱,根據命名策略HandlerMethodMappingNamingStrategy<T>類型的屬性namingStrategy獲得。
對於url集,在getDirectUrls方法通過調用抽象方法getMappingPathPatterns獲得。
private List<String> getDirectUrls(T mapping) {
List<String> urls = new ArrayList<>(1);
for (String path : getMappingPathPatterns(mapping)) {
if (!getPathMatcher().isPattern(path)) {
urls.add(path);
}
}
return urls;
}
2. RequestMappingInfoHandlerMapping
RequestMappingInfoHandlerMapping是AbstractHandlerMethodMapping<RequestMappingInfo>的子類,是所有匹配條件T爲RequestMappingInfo類型的HandlerMapping的抽象基類。
2.1 namingStrategy
protected RequestMappingInfoHandlerMapping() {
setHandlerMethodMappingNamingStrategy(new RequestMappingInfoHandlerMethodMappingNamingStrategy());
}
可以看到,默認的命名策略是RequestMappingInfoHandlerMethodMappingNamingStrategy,其命名邏輯如下。
//RequestMappingInfoHandlerMethodMappingNamingStrategy#getName
@Override
public String getName(HandlerMethod handlerMethod, RequestMappingInfo mapping) {
//如果已經有name,直接使用
if (mapping.getName() != null) {
return mapping.getName();
}
StringBuilder sb = new StringBuilder();
String simpleTypeName = handlerMethod.getBeanType().getSimpleName();
for (int i = 0 ; i < simpleTypeName.length(); i++) {
if (Character.isUpperCase(simpleTypeName.charAt(i))) {
sb.append(simpleTypeName.charAt(i));
}
}
sb.append(SEPARATOR).append(handlerMethod.getMethod().getName());
return sb.toString();
}
首選使用匹配條件的名稱,否則命名方式爲類名中的大寫字母 + # + 方法名。
2.2 getMatchingMapping
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
return info.getMatchingCondition(request);
}
匹配的url通過匹配通過RequestMappingInfo獲得。
3. RequestMappingInfo
RequestMappingInfo是RequestMappingInfoHandlerMapping及其子類RequestMappingHandlerMapping的泛型類,用來匹配http請求。
//省略方法
public final class RequestMappingInfo implements RequestCondition\<RequestMappingInfo\> {
@Nullable
//名稱
private final String name;
//請求pattern,用來匹配url
private final PatternsRequestCondition patternsCondition;
//請求方法,如GET|POST等等
private final RequestMethodsRequestCondition methodsCondition;
//請求參數,必須包含特定參數才能匹配
private final ParamsRequestCondition paramsCondition;
//請求頭,必須包含特定值才能匹配
private final HeadersRequestCondition headersCondition;
//consumes,請求的content-type
private final ConsumesRequestCondition consumesCondition;
//produces,響應的content-type
private final ProducesRequestCondition producesCondition;
//自定義的條件
private final RequestConditionHolder customConditionHolder;
}
一般在日常開發中,RequestMappingInfo與註解RequestMapping中的屬性一一對應,具體如RequestMappingHandlerMapping#createRequestMappingInfo(RequestMapping, RequestCondition<?>)所示
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();
}
4. RequestMappingHandlerMapping
RequestMappingHandlerMapping是RequestMappingInfoHandlerMapping的子類,同樣的將RequestMappingInfo作爲泛型類,並且RequestMappingInfo對象基於註解RequestMapping生成。
1. afterProperties
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();
}
RequestMappingHandlerMapping重寫了afterProperties方法
(1)config屬性的初始化
config屬性用於基於RequestMapping註解生成RequestMappingInfo
(2)調用父類的afterProperties方法
即AbstractHandlerMethodMapping類的afterProperties方法
2. getMappingForMethod
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
//基於方法生成匹配條件RequestMappingInfo
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
//基於類生成匹配條件RequestMappingInfo
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
//方法和類上的條件組合
info = typeInfo.combine(info);
}
}
return info;
}
根據方法和類調用createRequestMappingInfo方法生成RequestMappingInfo對象並組合返回。
對於兩個RequestMappingInfo對象的組合,不同的屬性的組合方式不同,可能是覆蓋(如consumes, produces)、並集(如params, headers, methods)、字符串相加(如pattern),當然也可以自定義實現組合邏輯。
3. createRequestMappingInfo
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
//獲取註解
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
//獲取condition,默認返回null
RequestCondition<?> condition = (element instanceof Class ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));、
//根據註解生成RequestMappingInfo對象
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}