SpringMVC核心組件HandlerMapping,你清楚了嗎?
概述
當(dāng)一個請求過來后Spring是如何進(jìn)行處理的?下面簡單的羅列下請個的過程中核心組件
SpringMVC處理的流程:
- DispatcherServlet 所有請求的入口
- HandlerMapping 將請求地址與處理程序關(guān)聯(lián)
- HandlerAdapter 真正的處理程序,如執(zhí)行上一步中對應(yīng)的處理程序
- HandlerMethodArgumentResolver 對參數(shù)進(jìn)行解析,這里面還涉及到很多其它東西
- HanlderMethodReturnValueHandler 對返回值進(jìn)行輸出處理
- ViewResolver 當(dāng)上一步返回結(jié)果為ModelAndView時會應(yīng)用視圖解析器
一個請求的處理過程
獲取HandlerMapping
該步從容器中獲取所有的HandlerMapping對象。
- public class DispatcherServlet extends FrameworkServlet {
- private List<HandlerMapping> handlerMappings;
- private void initHandlerMappings(ApplicationContext context) {
- // 在ApplicationContext中查找所有HandlerMappings,包括祖先上下文。
- Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
- if (!matchingBeans.isEmpty()) {
- this.handlerMappings = new ArrayList<>(matchingBeans.values());
- AnnotationAwareOrderComparator.sort(this.handlerMappings);
- }
- }
- }
查找HandlerMapping
該步從獲取的HandlerMapping中查找適合當(dāng)前請求的HandlerMapping。
- public class DispatcherServlet extends FrameworkServlet {
- private List<HandlerMapping> handlerMappings;
- protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
- HandlerExecutionChain mappedHandler = null;
- // 查找能夠處理當(dāng)前請求HandlerMapping對象,主要就是根據(jù)請求的URI
- mappedHandler = getHandler(processedRequest);
- }
- protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
- if (this.handlerMappings != null) {
- // HandlerMapping 實現(xiàn)了Ordered接口,是由順序的,那在這里,誰先匹配誰就處理
- for (HandlerMapping mapping : this.handlerMappings) {
- // 在這個過程中會通過查找到的HandlerMapping對象,然后獲取合適的處理程序(可能是個Bean對象或是HandlerMethod對象等)
- HandlerExecutionChain handler = mapping.getHandler(request);
- if (handler != null) {
- return handler;
- }
- }
- }
- return null;
- }
- }
系統(tǒng)默認(rèn)有如下5個HandlerMapping
- RequestMappingHandlerMapping
- BeanNameUrlHandlerMapping
- RouterFunctionMapping
- SimpleUrlHandlerMapping
- WelcomePageHandlerMapping
一般默認(rèn)都是RequestMappingHandlerMapping匹配
接下來看看是如何進(jìn)行匹配的
調(diào)用父類AbstractHandlerMapping#getHandler方法,父類中的這個方法中定義了特定的邏輯,而針對每種不同的HandlerMapping實現(xiàn)是需要具體的子類來實現(xiàn)AbstractHandlerMapping#getHandlerInternal方法
- public abstract class AbstractHandlerMapping {
- public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
- Object handler = getHandlerInternal(request);
- // ...
- HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
- // ...
- return executionChain;
- }
- }
- public abstract class AbstractHandlerMethodMapping {
- protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
- // 獲取請求地址
- String lookupPath = initLookupPath(request);
- try {
- // 根據(jù)請求地址查詢對應(yīng)的HandlerMethod
- HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
- return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
- }
- // ...
- }
- protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
- List<Match> matches = new ArrayList<>();
- // 在已注冊的Mapping中根據(jù)請求的url進(jìn)行查找
- // 這樣查找的this.pathLookup.get(urlPath);
- List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
- if (!matches.isEmpty()) {
- Match bestMatch = matches.get(0);
- // ...
- handleMatch(bestMatch.mapping, lookupPath, request);
- return bestMatch.getHandlerMethod();
- }
- // ...
- }
- }
到這里就是查找處理請求的HandlerMethod對象。接下來看看系統(tǒng)是如何進(jìn)行初始化所有的HandlerMethod
初始化HandlerMethod
- public class RequestMappingHandlerMapping {
- public void afterPropertiesSet() {
- // ...
- super.afterPropertiesSet();
- }
- }
- public abstract class AbstractHandlerMethodMapping {
- public void afterPropertiesSet() {
- initHandlerMethods();
- }
- protected void initHandlerMethods() {
- // getCandidateBeanNames獲取容器中的所有Bean
- for (String beanName : getCandidateBeanNames()) {
- if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
- processCandidateBean(beanName);
- }
- }
- handlerMethodsInitialized(getHandlerMethods());
- }
- protected void processCandidateBean(String beanName) {
- Class<?> beanType = null;
- try {
- // 根據(jù)BeanName獲取對應(yīng)的Class
- beanType = obtainApplicationContext().getType(beanName);
- }
- // ...
- // isHandler方法判斷當(dāng)前的類是否符合條件,該方法在RequestMappingHandlerMapping中實現(xiàn)
- // isHandler方法用處就是判斷當(dāng)前的Class@Controller或者@RequestMapping注解
- // 這樣就將所有的@Controller與RequestMappingHandlerMapping關(guān)聯(lián)一起了。
- if (beanType != null && isHandler(beanType)) {
- // 查找所有的HandlerMethod
- detectHandlerMethods(beanName);
- }
- }
- protected void detectHandlerMethods(Object handler) {
- Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass());
- if (handlerType != null) {
- Class<?> userType = ClassUtils.getUserClass(handlerType);
- // 查找Class中的所有方法
- Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) method -> {
- try {
- // 將每一個符合條件的方法(方法上有@RequestMapping注解的)
- // 封裝到RequestMappingInfo對象中
- return getMappingForMethod(method, userType);
- }
- // ...
- });
- methods.forEach((method, mapping) -> {
- Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
- // 將找到的所有Method進(jìn)行注冊添加到Map中
- registerHandlerMethod(handler, invocableMethod, mapping);
- });
- }
- }
- protected void registerHandlerMethod(Object handler, Method method, T mapping) {
- this.mappingRegistry.register(mapping, handler, method);
- }
- class MappingRegistry {
- // T : RequestMappingInfo, handler: 字符串(usersController)Bean名稱,method:請求方法對象
- public void register(T mapping, Object handler, Method method) {
- // 創(chuàng)建HandlerMethod對象
- HandlerMethod handlerMethod = createHandlerMethod(handler, method);
- // ...
- for (String path : directPaths) {
- // 緩存上,在請求到來的時候 會從這個pathLookup集合中查找
- this.pathLookup.add(path, mapping);
- }
- }
- }
- }