当前位置: 首页>后端>正文

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

https://www.xamrdz.com/backend/32b1929076.html

相关文章: