spring MVC RequestMappingHandlerMapping解析
spring MVC RequestMappingHandlerMapping解析
getHandler(HttpServletRequest request)
在doDispatch(HttpServletRequest request, HttpServletResponse response)中,調用過getHandler(HttpServletRequest request)。
DispatcherServlet)的getHandler(HttpServletRequest request方法,該方法遍歷所有HandlerMapping并找到匹配的HandlerExecutionChain并返回HandlerExecutionChain對象。源碼如下:
@Nullableprotected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {if (this.handlerMappings != null) {//遍歷HandlerMappingfor (HandlerMapping mapping : this.handlerMappings) {//找到匹配的HandlerExecutionChainHandlerExecutionChain handler = mapping.getHandler(request);if (handler != null) {return handler;}}}return null;}HandlerExecutionChain
我們打開HandlerExecutionChain看一下,發現他是一個包含Handler(我們平時叫Handler,后面你會發現其實他是HandlerMethod的子類)和HandlerInterceptor。
根據源碼的注釋,我們可以得知這個HandlerExecutionChain是一個調用執行鏈,包含了HandlerInterceptor和handler。
/*** Handler execution chain, consisting of handler object and any handler interceptors.* Returned by HandlerMapping's {@link HandlerMapping#getHandler} method.** @author Juergen Hoeller* @since 20.06.2003* @see HandlerInterceptor*/ public class HandlerExecutionChain {private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);//handlerprivate final Object handler;//HandlerInterceptor數組@Nullableprivate HandlerInterceptor[] interceptors;//HandlerInterceptor的List@Nullableprivate List<HandlerInterceptor> interceptorList;//interceptor的下標,應該是代表執行到哪一個HandlerInterceptorprivate int interceptorIndex = -1;RequestMappingHandlerMapping
HandlerMapping是一個接口,HandlerMapping的實現類是有十分多的,RequestMappingHandlerMapping類做為重點介紹。根據RequestMappingHandlerMapping的注釋,該類用于創建@RequestMapping和@Controller注解的實例。
RequestMappingHandlerMapping的初始化
找到RequestMappingHandlerMapping的afterPropertiesSet()方法,這個方法來自InitializingBean接口,根據Bean的生命周期可以知道,當做完bean屬性填充之后我們會調用InitializingBean.afterPropertiesSet()
@Override @SuppressWarnings("deprecation") public void afterPropertiesSet() {//創建RequestMappingInfo.BuilderConfiguration對象,創建配置信息用this.config = new RequestMappingInfo.BuilderConfiguration();//調用setter設置各種屬性this.config.setUrlPathHelper(getUrlPathHelper());this.config.setPathMatcher(getPathMatcher());this.config.setSuffixPatternMatch(useSuffixPatternMatch());this.config.setTrailingSlashMatch(useTrailingSlashMatch());this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());this.config.setContentNegotiationManager(getContentNegotiationManager());//調用父類AbstractHandlerMethodMapping的afterPropertiesSet()super.afterPropertiesSet(); }找到AbstractHandlerMethodMapping(一個抽象類)的afterPropertiesSet()。我講一下,這個afterPropertiesSet()做了什么操作,代碼有點長,但是核心操作就幾個:
- 調用getCandidateBeanNames()從上下文中掃描合適的bean,并獲取候選bean的名字(@Controller注解的bean)
- 調用processCandidateBean(String beanName)從上下文中獲取對應beanName的beanType,并將beanType傳遞給isHandler(Class<?> beanType)
- isHandler(Class<?> beanType)判斷是否@RequestMapping和@Controller注解的實例
- 經過isHandler(Class<?> beanType)過濾的beanName會并將符合要求的beanName丟給detectHandlerMethods(Object handler) 方法處理。
- detectHandlerMethods(Object handler)會找處指定的handler bean中的handler methods(符合的@RequestMapping注解過的方法),并調用registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping)去注冊方法
- 調用getHandlerMethods(),獲取從this.mappingRegistry獲取HandlerMethods
- 最后調用handlerMethodsInitialized()作一些初始化后的日志工作
因為調用方法比較多,我分開展示:
initHandlerMethods()
/*** Detects handler methods at initialization.* @see #initHandlerMethods*/@Overridepublic void afterPropertiesSet() {//去調用下面的initHandlerMethods()initHandlerMethods();}/*** Scan beans in the ApplicationContext, detect and register handler methods.* @see #getCandidateBeanNames()* @see #processCandidateBean* @see #handlerMethodsInitialized*/protected void initHandlerMethods() {//getCandidateBeanNames()從上下文中掃描合適的bean的名字for (String beanName : getCandidateBeanNames()) {//必須不帶“scopedTarget.”前綴的bean名if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {//發現并注冊handler methodsprocessCandidateBean(beanName);}}//handlerMethodsInitialized()只是日志工作//getHandlerMethods()handlerMethodsInitialized(getHandlerMethods());}getCandidateBeanNames()
中上下文中獲取候選的bean
/*** Determine the names of candidate beans in the application context.* @since 5.1* @see #setDetectHandlerMethodsInAncestorContexts* @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors*///從上下文中掃描合適的bean的名字protected String[] getCandidateBeanNames() {return (this.detectHandlerMethodsInAncestorContexts ?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :obtainApplicationContext().getBeanNamesForType(Object.class));}processCandidateBean(String beanName)
/*** Determine the type of the specified candidate bean and call* {@link #detectHandlerMethods} if identified as a handler type.* <p>This implementation avoids bean creation through checking* {@link org.springframework.beans.factory.BeanFactory#getType}* and calling {@link #detectHandlerMethods} with the bean name.* @param beanName the name of the candidate bean* @since 5.1* @see #isHandler* @see #detectHandlerMethods*///發現并注冊handler methodsprotected void processCandidateBean(String beanName) {Class<?> beanType = null;try {//從上下文中獲取對應beanName的bean的TypebeanType = obtainApplicationContext().getType(beanName);}catch (Throwable ex) {// An unresolvable bean type, probably from a lazy bean - let's ignore it.if (logger.isTraceEnabled()) {logger.trace("Could not resolve type for bean '" + beanName + "'", ex);}}//使用isHandler(Class<?> beanType)過濾符合要求的Handlerif (beanType != null && isHandler(beanType)) {//發現HandlerMethod,最終會調用父類方法注冊到this.mappingRegistry中detectHandlerMethods(beanName);}}isHandler(Class<?> beanType)
判斷哪些是符合要求的Handler
//判斷哪些是符合要求的Handler,從該方法可以得知要的是@Controller和@RequestMapping的bean @Override protected boolean isHandler(Class<?> beanType) {return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); }detectHandlerMethods(Object handler)
發現HandlerMethod,最終會調用父類方法注冊到this.mappingRegistry中
/*** Look for handler methods in the specified handler bean.* @param handler either a bean name or an actual handler instance* @see #getMappingForMethod*///找handler bean中的handler methodsprotected 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 {return getMappingForMethod(method, userType);}catch (Throwable ex) {throw new IllegalStateException("Invalid mapping on handler class [" +userType.getName() + "]: " + method, ex);}});if (logger.isTraceEnabled()) {logger.trace(formatMappings(userType, methods));}methods.forEach((method, mapping) -> {Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); //核心是這個,注冊HandlerMethod到mapping中registerHandlerMethod(handler, invocableMethod, mapping);});}}getHandlerMethods()
獲取已經注冊的Handler,你會發現HandlerMethod
/*** Return a (read-only) map with all mappings and HandlerMethod's.*/ public Map<T, HandlerMethod> getHandlerMethods() {this.mappingRegistry.acquireReadLock();try {return Collections.unmodifiableMap(this.mappingRegistry.getMappings());}finally {this.mappingRegistry.releaseReadLock();} }找到RequestMappingHandlerMapping的兩個register方法,看看他注冊了什么:
- registerMapping(RequestMappingInfo mapping, Object handler, Method method)
- registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping)
你會發現兩個register方法主要是調用父類的register方法,并且跟新RequestMappingInfo中的ConsumesCondition,
//一個RequestMappingInfo對象(點開會發現各種XXXRequestCondition) //一個handler //一個method,調用的方法 @Override public void registerMapping(RequestMappingInfo mapping, Object handler, Method method) {//注冊,最終會注冊到this.mappingRegistry中super.registerMapping(mapping, handler, method);//updateConsumesCondition主要是將method中形參列表加到RequestMappingInfo中的ConsumesConditionupdateConsumesCondition(mapping, method); }@Override protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {super.registerHandlerMethod(handler, method, mapping);updateConsumesCondition(mapping, method); }AbstractHandlerMapping
AbstractHandlerMapping是AbstractHandlerMethodMapping父類。
AbstractHandlerMapping提供了getHandler(HttpServletRequest request)用于獲取HandlerExecutionChain(Handler) ,所以RequestMappingHandlerMapping最終獲取的HandlerExecutionChain來自AbstractHandlerMapping提供的getHandler(HttpServletRequest request)
/*** Look up a handler for the given request, falling back to the default* handler if no specific one is found.* @param request current HTTP request* @return the corresponding handler instance, or the default handler* @see #getHandlerInternal*/@Override@Nullablepublic final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {Object handler = getHandlerInternal(request);if (handler == null) {handler = getDefaultHandler();}if (handler == null) {return null;}// Bean name or resolved handler?if (handler instanceof String) {String handlerName = (String) handler;handler = obtainApplicationContext().getBean(handlerName);}HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);if (logger.isTraceEnabled()) {logger.trace("Mapped to " + handler);}else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {logger.debug("Mapped to " + executionChain.getHandler());}if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);config = (config != null ? config.combine(handlerConfig) : handlerConfig);executionChain = getCorsHandlerExecutionChain(request, executionChain, config);}return executionChain;}總結
以上是生活随笔為你收集整理的spring MVC RequestMappingHandlerMapping解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Via浏览器:和Chrome一样简洁,却
- 下一篇: Spring Boot解决跨域问题