SpringMVC原始碼之Handler註冊、獲取以及請求controller中方法

曹自標發表於2020-11-18

總結

  1. 對requestMappingHandlerMapping進行initializeBean時register Handler
  2. http開始請求時,initHandlerMappings,DispatcherServlet 中handlerMappings賦值完成
  3. 最後在DispatcherServlet#doDispatch()中,用對應的HandlerAdapter和Handler通過反射去請求controller中方法

對requestMappingHandlerMapping進行initializeBean時register Handler

呼叫鏈:

AbstractApplicationContext#refresh() --> AbstractApplicationContext#finishBeanFactoryInitialization() --> DefaultListableBeanFactory#preInstantiateSingletons() --> AbstractBeanFactory#getBean() --> AbstractBeanFactory#doGetBean() --> AbstractAutowireCapableBeanFactory#createBean() --> AbstractAutowireCapableBeanFactory#doCreateBean() --> AbstractAutowireCapableBeanFactory#initializeBean() --> AbstractAutowireCapableBeanFactory#invokeInitMethods() --> RequestMappingHandlerMapping#afterPropertiesSet() --> AbstractHandlerMethodMapping#afterPropertiesSet() --> AbstractHandlerMethodMapping#initHandlerMethods() --> AbstractHandlerMethodMapping#processCandidateBean --> AbstractHandlerMethodMapping#detectHandlerMethods() --> RequestMappingHandlerMapping#registerHandlerMethod() --> AbstractHandlerMethodMapping#registerHandlerMethod()

在AbstractHandlerMethodMapping#initHandlerMethods()中先獲取所有的beanName,再挑選出符合條件的進行處理

protected void initHandlerMethods() {
    //獲取容器中所有beanName
	for (String beanName : getCandidateBeanNames()) {
		if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
			processCandidateBean(beanName);
		}
	}
	handlerMethodsInitialized(getHandlerMethods());
}

判斷是Handler的才繼續呼叫detectHandlerMethods方法

protected void processCandidateBean(String beanName) {
	Class<?> beanType = null;
    ......
	if (beanType != null && isHandler(beanType)) {
		detectHandlerMethods(beanName);
	}
}

滿足handler的條件是(RequestMappingHandlerMapping#isHandler()):@Controller或@RequestMapping進行註解

@Override
protected boolean isHandler(Class<?> beanType) {
	return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
			AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

滿足條件的,進行註冊
RequestMappingHandlerMapping#registerHandlerMethod()

@Override
protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
	super.registerHandlerMethod(handler, method, mapping);
	updateConsumesCondition(mapping, method);
}

AbstractHandlerMethodMapping#registerHandlerMethod()

protected void registerHandlerMethod(Object handler, Method method, T mapping) {
	this.mappingRegistry.register(mapping, handler, method);
}

完成註冊。AbstractHandlerMethodMapping#register()

public void register(T mapping, Object handler, Method method) {
	this.readWriteLock.writeLock().lock();
	try {
		HandlerMethod handlerMethod = createHandlerMethod(handler, method);
		validateMethodMapping(handlerMethod, mapping);

		Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
		for (String path : directPaths) {
			this.pathLookup.add(path, mapping);
		}

		String name = null;
		if (getNamingStrategy() != null) {
			name = getNamingStrategy().getName(handlerMethod, mapping);
			addMappingName(name, handlerMethod);
		}

		CorsConfiguration config = initCorsConfiguration(handler, method, mapping);
		if (config != null) {
			config.validateAllowCredentials();
			this.corsLookup.put(handlerMethod, config);
		}

		this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directPaths, name));
	}
	finally {
		this.readWriteLock.writeLock().unlock();
	}
}

initHandlerMappings

呼叫鏈:

Standardwrapper#initServlet() --> HttpServletBean#init() --> FrameworkServlet#initServletBean() --> FrameworkServlet#initWebApplicationContext() --> DispatcherServlet#onRefresh() --> DispatcherServlet#initStrategies() -->
DispatcherServlet#initHandlerMappings()

http請求時,先initHandlerMappings.
matchingBeans會儲存獲取到所有符合條件的,再給handlerMappings賦值

private void initHandlerMappings(ApplicationContext context) {
	this.handlerMappings = null;

	if (this.detectAllHandlerMappings) {
		// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
		Map<String, HandlerMapping> matchingBeans =
				BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
		if (!matchingBeans.isEmpty()) {
			this.handlerMappings = new ArrayList<>(matchingBeans.values());
			// We keep HandlerMappings in sorted order.
			AnnotationAwareOrderComparator.sort(this.handlerMappings);
		}
	}
}

其中BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);會先呼叫AbstractApplicationContext#getBeansOfType(),再呼叫DefaultListableBeanFactory#getBeansOfType()

先獲取beanName requestMappingHandlerMapping,再根據beanName(requestMappingHandlerMapping)從容器獲取beanInstance。最後put到result中返回

@Override
@SuppressWarnings("unchecked")
public <T> Map<String, T> getBeansOfType(
		@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException {
    //獲取requestMappingHandlerMapping
	String[] beanNames = getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
	Map<String, T> result = CollectionUtils.newLinkedHashMap(beanNames.length);
	for (String beanName : beanNames) {
		try {
		    ////再根據beanName(requestMappingHandlerMapping)從容器獲取beanInstance
			Object beanInstance = getBean(beanName);
			if (!(beanInstance instanceof NullBean)) {
				result.put(beanName, (T) beanInstance);
			}
		}
	......
	return result;
}

從而在initHandlerMappings給handlerMappings賦值完成

this.handlerMappings = new ArrayList<>(matchingBeans.values());

doDispatch

獲取當前請求的handler和HandlerAdapter

DispatcherServlet#doDispatch()

mappedHandler = getHandler(processedRequest);

DispatcherServlet#getHandler()

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;
}

通過反射方式請求controller中方法:

// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

doDispatch程式碼附錄

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	HttpServletRequest processedRequest = request;
	HandlerExecutionChain mappedHandler = null;
	boolean multipartRequestParsed = false;

	WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

	try {
		ModelAndView mv = null;
		Exception dispatchException = null;

		try {
			processedRequest = checkMultipart(request);
			multipartRequestParsed = (processedRequest != request);

			// Determine handler for the current request.
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null) {
				noHandlerFound(processedRequest, response);
				return;
			}

			// Determine handler adapter for the current request.
			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

			// Process last-modified header, if supported by the handler.
			String method = request.getMethod();
			boolean isGet = "GET".equals(method);
			if (isGet || "HEAD".equals(method)) {
				long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
				if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
					return;
				}
			}

			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}

			// Actually invoke the handler.
			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

			if (asyncManager.isConcurrentHandlingStarted()) {
				return;
			}

			applyDefaultViewName(processedRequest, mv);
			mappedHandler.applyPostHandle(processedRequest, response, mv);
		}
		catch (Exception ex) {
			dispatchException = ex;
		}
		catch (Throwable err) {
			// As of 4.3, we're processing Errors thrown from handler methods as well,
			// making them available for @ExceptionHandler methods and other scenarios.
			dispatchException = new NestedServletException("Handler dispatch failed", err);
		}
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}
	catch (Exception ex) {
		triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
	}
	catch (Throwable err) {
		triggerAfterCompletion(processedRequest, response, mappedHandler,
				new NestedServletException("Handler processing failed", err));
	}
	finally {
		if (asyncManager.isConcurrentHandlingStarted()) {
			// Instead of postHandle and afterCompletion
			if (mappedHandler != null) {
				mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
			}
		}
		else {
			// Clean up any resources used by a multipart request.
			if (multipartRequestParsed) {
				cleanupMultipart(processedRequest);
			}
		}
	}
}

相關文章