spring mvc源码分析之请求分发

9 篇文章 0 订阅
7 篇文章 0 订阅

前言

在使用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 遍历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.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.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.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);
			}
	}
}

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

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;
				}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值