前言
在使用SpringMvc
时,通过Controller
跟RequestMapping
,就能实现网络请求的处理。那么,这是怎么实现的呢?请求是如何从Tomcat
进入到controller
里的方法的呢?
核心流程概览
宏观上看,流程如下:
- 创建
DispatcherServlet
实例 - 创建
Tomcat
实例 - 通过
ServletContainerInitializer
以及ServletContextInitializer
将DispatcherServlet
注册到Tomcat
的Servlet
容器里 - 将
HandlerMapping
绑定到DispatcherServlet
- 请求通过
Tomcat
进到DispatcherServlet
-
DispatcherServlet
根据request path
到HandlerMapping
查找请求处理方法
源码分析
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
注册到Tomcat
的Servlet
容器里
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
-
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;
}
}