• spring mvc源码分析之请求分发


    前言

    在使用SpringMvc时,通过ControllerRequestMapping,就能实现网络请求的处理。那么,这是怎么实现的呢?请求是如何从Tomcat进入到controller里的方法的呢?

    核心流程概览

    宏观上看,流程如下:

    1. 创建DispatcherServlet实例
    2. 创建Tomcat实例
    3. 通过ServletContainerInitializer以及ServletContextInitializerDispatcherServlet注册到TomcatServlet容器里
    4. HandlerMapping绑定到DispatcherServlet
    5. 请求通过Tomcat进到DispatcherServlet
    6. DispatcherServlet根据request pathHandlerMapping查找请求处理方法

    源码分析

    1. 注册controller

    Spring在初始化RequestMappingHandlerMapping这个Bean时会将Controller层带有RequestMapping等相关注解的方法跟注解信息的PATH分别作为key value注册到RequestMappingHandlerMapping中。然后RequestMappingHandlerMapping会在第一次请求到来时被注册到DispatcherServlet

    1.1 初始化RequestMappingHandlerMapping

    RequestMappingHandlerMapping 继承了InitializingBean,在Spring创建RequestMappingHandlerMapping的实例时会去调用其afterPropertiesSet方法进行初始化

    public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
    		implements AutowireCapableBeanFactory {
    
    		protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
    					throws Throwable {
    					
    			//判断当前bean是否继承了InitializingBean
    			boolean isInitializingBean = (bean instanceof InitializingBean);
    	
    			if (isInitializingBean) {
    				//初始化
    				((InitializingBean) bean).afterPropertiesSet();
    			}
    		}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    1.2 遍历Controller

    RequestMappingHandlerMapping会把所有的Spring Bean对应的类里有Controller或者RequestMapping注解的类拿出来处理

    public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
    
    		protected void processCandidateBean(String beanName) {
    		
    				Class<?> beanType = null;
    				try {
    					beanType = obtainApplicationContext().getType(beanName);
    				}
    				catch (Throwable ex) {
    					...
    				}
    				//只处理有相应注解的bean
    				if (beanType != null && isHandler(beanType)) {
    					detectHandlerMethods(beanName);
    				}
    			}
    		
    		//判断是否有相应注解
    		protected boolean isHandler(Class<?> beanType) {
    				return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
    						AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    			}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    1.3 生成RequestMappingInfo

    把1.2里得到的类里的所有带有RequestMapping注解的方法拿出来包装成RequestMappingInfo 并塞到RequestMappingHandlerMapping内部的hashMap

    public final class MethodIntrospector {
    
    		public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
    				final Map<Method, T> methodMap = new LinkedHashMap<>();
    				Set<Class<?>> handlerTypes = new LinkedHashSet<>();
    				Class<?> specificHandlerType = null;
    		
    				handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));
    		
    				for (Class<?> currentHandlerType : handlerTypes) {
    					final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
    		
    					//通过反射找到targetType下的所有method
    					ReflectionUtils.doWithMethods(currentHandlerType, method -> {
    						Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
    						//判断method上是否有@RequestMapping,没有则返回null
    						T result = metadataLookup.inspect(specificMethod);
    						if (result != null) {
    							//如果是桥接方法,就返回被桥接的方法。否则返回specificMethod
    							Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
    							//如果specificMethod是桥接方法,则不添加到methodMap中。否则同一个方法就会被添加两次
    							if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
    								methodMap.put(specificMethod, result);
    							}
    						}
    					}, ReflectionUtils.USER_DECLARED_METHODS);
    				}
    		
    				return methodMap;
    			}
    }
    
    public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
    
    		// metadataLookup.inspect(specificMethod)是MetadataLookup#inspect的一个匿名实现
    		protected void detectHandlerMethods(Object handler) {
    				...
    		
    				Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
    							(MethodIntrospector.MetadataLookup<T>) method -> {
    								//根据方法是否被RequestMapping.class标注来判断方法是否可以被注册
    								return getMappingForMethod(method, userType);
    							});
    		
    		    methods.forEach((method, mapping) -> {
    						Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
    				    	//准备注册
    						registerHandlerMethod(handler, invocableMethod, mapping);
    					});
    				...
    			}
    }
    
    public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
    		implements MatchableHandlerMapping, EmbeddedValueResolverAware {
    
    		//判断方法是否应该被注册
    		private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
    				//判断方法上是否有RequestMapping.class
    				RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
    				RequestCondition<?> condition = (element instanceof Class ?
    						getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
    		    	//创建RequestMappingInfo
    				return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
    			}
    }
    
    public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
    		//注册
    		public void register(T mapping, Object handler, Method method) {
    					...
    
    	        //把类名handler跟方法method包装成一个HandlerMethod对象
    					HandlerMethod handlerMethod = createHandlerMethod(handler, method);
    	
    					//把方法注解里的path跟mapping的关系保存下来,
    					//后面访问的时候会先从httpRequest解析出path,再根据path找到mapping
    					Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
    					for (String path : directPaths) {
    						this.pathLookup.add(path, mapping);
    					}
    	
    					//mapping是上面创建的RequestMappingInfo
    					this.registry.put(mapping,
    							new MappingRegistration<>(mapping, handlerMethod, directPaths, name, corsConfig != null));
    			}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87

    1.4 注册HandlerMapping

    HandlerMapping注册到DispatcherServlet。在第一次请求时进行初始化时触发

    public class DispatcherServlet extends FrameworkServlet {
    
    		private void initHandlerMappings(ApplicationContext context) {
    				this.handlerMappings = null;
    		
    				if (this.detectAllHandlerMappings) {
    					//从spring上下文里拿到所有实现了HandlerMapping的bean
    					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);
    					}
    				}
    			}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    1.5 注册DispatcherServlet

    DispatcherServlet 注册到TomcatServlet容器里

    public class ServletWebServerApplicationContext extends GenericWebApplicationContext
    		implements ConfigurableWebServerApplicationContext {		
    		
    		private void createWebServer() {
    				...
    				//创建webServer并添加下面的ServletContextInitializer匿名实现
    				this.webServer = factory.getWebServer(getSelfInitializer());
    				...
    		}
    
    		private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
    				return this::selfInitialize;
    		}
    
    		private void selfInitialize(ServletContext servletContext) throws ServletException {			
    			...
    			//找到所有实现了ServletContextInitializer接口的Spring bean
    			//这里拿到的是DispatcherServletRegistrationBean
    			//而DispatcherServletRegistrationBean里持有DispatcherServlet的Spring bean
    			for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
    				//将DispatcherServlet注册到Tomcat的Servlet容器中
    				beans.onStartup(servletContext);
    			}
    		}
    }
    
    @Configuration(proxyBeanMethods = false)
    protected static class DispatcherServletRegistrationConfiguration {
    
    		@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
    		public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
    				WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
    			//通过DispatcherServlet创建DispatcherServletRegistrationBean
    			DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
    					webMvcProperties.getServlet().getPath());
    			return registration;
    		}
    }
    
    public abstract class RegistrationBean implements ServletContextInitializer, Ordered {
    		@Override
    		public final void onStartup(ServletContext servletContext) throws ServletException {
    			//注册DispatcherServlet。最终会注册到StandardWrapper#setServlet
    			register(description, servletContext);
    		}
    }
    
    //Tomcat启动时触发
    class TomcatStarter implements ServletContainerInitializer {	
    
    	public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException {
    		//这里会拿到上面添加的匿名ServletContextInitializer
    		for (ServletContextInitializer initializer : this.initializers) {
    				initializer.onStartup(servletContext);
    			}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    2. 访问controller

    2.1 请求进入DispatcherServlet

    1. Tomcat从Servlet容器中取出DispatcherServlet,并将请求交给DispatcherServlet
    public class DispatcherServlet extends FrameworkServlet {
    		protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    				//根据request的url跟http method从RequestMappingHandlerMapping.registry中获取对应的
    				//请求处理器
    				mappedHandler = getHandler(processedRequest);
    		
    				...
    		
    				//调用请求处理方法		
    				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    			}
    
    		protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    				if (this.handlerMappings != null) {
    		
    					//遍历大步骤1小步骤4时注册进来的handlerMappings
    					for (HandlerMapping mapping : this.handlerMappings) {
    		
    						//根据request path查找handler
    						HandlerExecutionChain handler = mapping.getHandler(request);
    						if (handler != null) {
    							return handler;
    						}
    					}
    				}
    				return null;
    			}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    2.2 查找请求处理方法

    RequestMappingHandlerMapping 根据HttpServletRequest查找请求处理器

    public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
    
    		protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    				//解析出url的path
    				String lookupPath = initLookupPath(request);
    				this.mappingRegistry.acquireReadLock();
    				try {
    					//根据path找到对应的HandlerMethod
    					HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
    					return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    				}
    				finally {
    					this.mappingRegistry.releaseReadLock();
    				}
    			}
    		
    		protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    				List<Match> matches = new ArrayList<>();
    		
    				//通过lookupPath找到mapping
    				List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
    				if (directPathMatches != null) {
    					//根据mapping从RequestMappingHandlerMapping#registry里
    					//找到对应的RequestMappingInfo并包装成Match对象,放入matches中
    					addMatchingMappings(directPathMatches, matches, request);
    				}
    				
    				if (!matches.isEmpty()) {
    					Match bestMatch = matches.get(0);
    					
    					//从RequestMappingInfo获取HandlerMethod
    					return bestMatch.getHandlerMethod();
    				}
    			}
    		
    		private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
    				for (T mapping : mappings) {
    					T match = getMatchingMapping(mapping, request);
    					if (match != null) {
    						//根据mapping找到RequestMappingInfo并包装成Match对象
    						matches.add(new Match(match, this.mappingRegistry.getRegistrations().get(mapping)));
    					}
    				}
    			}
    		
    		public Map<T, MappingRegistration<T>> getRegistrations() {
    					//第一步里的registry
    					return this.registry;
    				}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
  • 相关阅读:
    使用 pm2 启动 nodejs 服务
    Spring Cloud Alibaba【OpenFeign实现服务降级、Dubbo实现服务生产者、 Dubbo消费者调用接口 】(三)
    选座位吧(10)
    使用TS进行Vue-Router的Meta类型扩展
    【Unity3D】UGUI之Dropdown
    健身用什么耳机比较好,盘点五款适合健身场景的耳机
    前端知识学习案例8-开发企业网站8-实现关于我们的部分1
    CSS 中的 HSL 和 HSLA 与 RGB 和 RGBA
    自然语言处理学习笔记(九)———— OVV Recall Rate与 IV Recall Rate
    Oracle VM VirtualBox 安装 Ubuntu Linux
  • 原文地址:https://blog.csdn.net/scientificCommunity/article/details/127574824