Spring source code analysis 6: processor mapping and processor adaptation processing

Time:2022-5-6

Spring source code analysis 6: processor mapping and processor adaptation processing

staySpring source code analysis 1: Spring MVC loading mechanismThere are some points to be resolved:

  1. ConfigurableWebApplicationContext.refreshRefresh context
  2. ApplicationContext.getBeanGet bean from context
  3. DispatcherServlet.propertiesPolicy processing defined in the file
  4. ContextLoader.propertiesPolicy processing defined in the file
  5. View.renderView rendering

Among them, articles 1, 2 and 4 have been published inSpring source code analysis II: context component (webapplicationcontext)In this section, let’s take a look at the following article 3:DispatcherServlet.propertiesPolicy processing defined in the file

DispatcherServlet.properties
The contents of the document are as follows:

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
    org.springframework.web.servlet.function.support.RouterFunctionMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
    org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
    org.springframework.web.servlet.function.support.HandlerFunctionAdapter


org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
    org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
    org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

DispatcherServlet.propertiesThe document indicates:

LocaleResolverThemeResolverFlashMapManagerThe strategy is relatively simple, so it will not be analyzed here

1. BeanNameUrlHandlerMapping

BeanNameUrlHandlerMapping
The main function of is to map URLs to beans

The inheritance relationship is as follows

- AbstractHandlerMapping
  - AbstractUrlHandlerMapping
    - AbstractDetectingUrlHandlerMapping
      - BeanNameUrlHandlerMapping

1.1. AbstractHandlerMapping

AbstractHandlerMapping
Its main functions are to support processor sorting, specify default processor, processor interception, etc

public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
        implements HandlerMapping, Ordered, BeanNameAware {
    //Get processor
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //Get matching processor
        Object handler = getHandlerInternal(request);
        //If there is no matching processor, the default processor is obtained
        if (handler == null) {
            handler = getDefaultHandler();
        }
        //No processor, return null
        if (handler == null) {
            return null;
        }
        //If the handler is a string, use it as a bean name to get the bean instance
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = obtainApplicationContext().getBean(handlerName);
        }

        //Get processor执行链
        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

        // ...  Code omission

        return executionChain;
    }

    //Get matching processor,子类实现
    protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;

    //Get processor执行链
    protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        //Create processor execution chain
        HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

        //Add connectors, such as security verification, CORS, CSRF, etc
        for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
            if (interceptor instanceof MappedInterceptor) {
                MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
                if (mappedInterceptor.matches(request)) {
                    chain.addInterceptor(mappedInterceptor.getInterceptor());
                }
            }
            else {
                chain.addInterceptor(interceptor);
            }
        }
        return chain;
    }
}

1.2. AbstractUrlHandlerMapping

AbstractUrlHandlerMapping
The main function of is to realize URL mapping

Let’s take a look at the registration of handler first

public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping implements MatchableHandlerMapping {
    //Container urlpath = > handler
    private final Map<String, Object> handlerMap = new LinkedHashMap<>();
    //Container urlpattern = > handler
    private final Map<PathPattern, Object> pathPatternHandlerMap = new LinkedHashMap<>();

    //Register a handler
    protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
        Object resolvedHandler = handler;

        //If the handler is a string, use it as a bean name to get the bean instance
        if (handler instanceof String) {
            String handlerName = (String) handler;
            ApplicationContext applicationContext = obtainApplicationContext();
            if (applicationContext.isSingleton(handlerName)) {
                resolvedHandler = applicationContext.getBean(handlerName);
            }
        }

        Object mappedHandler = this.handlerMap.get(urlPath);
        if (mappedHandler != null) {
            if (mappedHandler != resolvedHandler) {
                //It has been registered. An error is reported
            }
        }
        else {
            if (urlPath.equals("/")) {
                //Set as root processor, only match/
                setRootHandler(resolvedHandler);
            }
            else if (urlPath.equals("/*")) {
                //Set as default processor, match all
                setDefaultHandler(resolvedHandler);
            }
            else {
                //Put into container
                this.handlerMap.put(urlPath, resolvedHandler);
                if (getPatternParser() != null) {
                    //Into a pattern matching container
                    this.pathPatternHandlerMap.put(getPatternParser().parse(urlPath), resolvedHandler);
                }
            }
        }
    }
}

Let’s take a look at the acquisition of handler

public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping implements MatchableHandlerMapping {
    //Get matching processor
    @Override
    protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
        //Get the real path part
        String lookupPath = initLookupPath(request);
        Object handler;

        //Use pattern matching
        if (usesPathPatterns()) {
            RequestPath path = ServletRequestPathUtils.getParsedRequestPath(request);
            handler = lookupHandler(path, lookupPath, request);
        }
        //Direct matching path
        else {
            handler = lookupHandler(lookupPath, request);
        }

        //If not
        if (handler == null) {
            Object rawHandler = null;
            //If yes /, the root processor is called
            if (StringUtils.matchesCharacter(lookupPath, '/')) {
                rawHandler = getRootHandler();
            }
            //If not, get the default parser/*
            if (rawHandler == null) {
                rawHandler = getDefaultHandler();
            }
            if (rawHandler != null) {
                //If the handler is a string, use it as a bean name to get the bean instance
                if (rawHandler instanceof String) {
                    String handlerName = (String) rawHandler;
                    rawHandler = obtainApplicationContext().getBean(handlerName);
                }
                //The package handler is handlerexecutionchain
                handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
            }
        }
        return handler;
    }

    //Find processor
    protected Object lookupHandler(
            RequestPath path, String lookupPath, HttpServletRequest request) throws Exception {
        //Get the processor directly through lookuppath
        Object handler = getDirectMatch(lookupPath, request);
        //Return if it exists
        if (handler != null) {
            return handler;
        }

        //Using pattern matching
        List<PathPattern> matches = null;
        for (PathPattern pattern : this.pathPatternHandlerMap.keySet()) {
            if (pattern.matches(path.pathWithinApplication())) {
                matches = (matches != null ? matches : new ArrayList<>());
                matches.add(pattern);
            }
        }
        //If there is no matching pattern, null is returned
        if (matches == null) {
            return null;
        }

        // ...  Code omission

        //Get the first matching pattern
        PathPattern pattern = matches.get(0);
        //Get the first matching pattern处理器
        handler = this.pathPatternHandlerMap.get(pattern);
        //If the handler is a string, use it as a bean name to get the bean instance
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = obtainApplicationContext().getBean(handlerName);
        }

        //Extract the matching part of pattern, such as
        // '/docs/cvs/commit.html' and '/docs/cvs/commit.html' => ''
        // '/docs/*' and '/docs/cvs/commit' => 'cvs/commit'
        // '/docs/cvs/*.html' and '/docs/cvs/commit.html' => 'commit.html'
        // '/docs/**' and '/docs/cvs/commit' => 'cvs/commit'
        PathContainer pathWithinMapping = pattern.extractPathWithinPattern(path.pathWithinApplication());
        //The package handler is handlerexecutionchain
        return buildPathExposingHandler(handler, pattern.getPatternString(), pathWithinMapping.value(), null);
    }
}

1.3. AbstractDetectingUrlHandlerMapping

AbstractDetectingUrlHandlerMapping
Its main function is to detect the beans in the context and then register the handler

public abstract class AbstractDetectingUrlHandlerMapping extends AbstractUrlHandlerMapping {
    //After initializing the context, detect the beans in the context, and then register the handler
    @Override
    public void initApplicationContext() throws ApplicationContextException {
        super.initApplicationContext();
        detectHandlers();
    }

    //Detect the bean in the context, and then register the handler
    protected void detectHandlers() throws BeansException {
        ApplicationContext applicationContext = obtainApplicationContext();
        //Use object Class is to get all the beans
        String[] beanNames = (this.detectHandlersInAncestorContexts ?
                BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
                applicationContext.getBeanNamesForType(Object.class));

        //Traverse beannames
        for (String beanName : beanNames) {
            //Get multiple URL matches of a handler
            String[] urls = determineUrlsForHandler(beanName);
            //If the url = > bean matches, register
            //If beanname starts with a slash "/", it is considered a URL
            if (!ObjectUtils.isEmpty(urls)) {
                //Register URL and beanname
                registerHandler(urls, beanName);
            }
        }
    }


    //Get multiple URL matches of a handler,由子类实现
    protected abstract String[] determineUrlsForHandler(String beanName);
}

1.4. BeanNameUrlHandlerMapping

BeanNameUrlHandlerMapping
The main function of is to detect the URL of the handler

public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {
    //Detect the URL of the handler
    @Override
    protected String[] determineUrlsForHandler(String beanName) {
        List<String> urls = new ArrayList<>();
        //If beanname starts with /, it means URL
        if (beanName.startsWith("/")) {
            urls.add(beanName);
        }
        String[] aliases = obtainApplicationContext().getAliases(beanName);
        for (String alias : aliases) {
            //If the alias starts with /, it means URL
            if (alias.startsWith("/")) {
                urls.add(alias);
            }
        }
        return StringUtils.toStringArray(urls);
    }
}

2. RequestMappingHandlerMapping

RequestMappingHandlerMapping
The main function of is processing@RequestMappingAnd@Controllerannotation

The inheritance relationship is as follows

- AbstractHandlerMapping
  - AbstractHandlerMethodMapping
    - RequestMappingInfoHandlerMapping
      - RequestMappingHandlerMapping

2.1. AbstractHandlerMethodMapping

AbstractHandlerMethodMapping
The main function of is to define the mapping from request to handlermethod

Let’s take a look at the registration of handler first

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
    //Register a map
    public void registerMapping(T mapping, Object handler, Method method) {
        this.mappingRegistry.register(mapping, handler, method);
    }

    //When all attributes are injected, this method is called by the context environment for initialization
    @Override
    public void afterPropertiesSet() {
        initHandlerMethods();
    }

    //Initialize all processor methods
    protected void initHandlerMethods() {
        //Get all beans in the context
        for (String beanName : getCandidateBeanNames()) {
            //Beanname with "scopedtarget." start
            if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
                processCandidateBean(beanName);
            }
        }

        // ...  Code omission
    }

    //Processing bean
    protected void processCandidateBean(String beanName) {
        Class<?> beanType = null;
        try {
            beanType = obtainApplicationContext().getType(beanName);
        }
        catch (Throwable ex) {
            // ...  Code omission
        }
        //If there are ` @ requestmapping 'and ` @ controller' annotations, it is the processor
        if (beanType != null && isHandler(beanType)) {
            //Detection processor method
            detectHandlerMethods(beanName);
        }
    }

    //Detection processor method
    protected void detectHandlerMethods(Object handler) {
        //Get bean type
        Class<?> handlerType = (handler instanceof String ?
                obtainApplicationContext().getType((String) handler) : handler.getClass());

        if (handlerType != null) {
            Class<?> userType = ClassUtils.getUserClass(handlerType);
            //Find methods on bean types
            Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
                    (MethodIntrospector.MetadataLookup<T>) method -> {
                        try {
                            //The package is requestmappinginfo
                            return getMappingForMethod(method, userType);
                        }
                        catch (Throwable ex) {
                            // ...  Code omission
                        }
                    });

            methods.forEach((method, mapping) -> {
                //Register processor mappings using mappingregistry
                registerHandlerMethod(handler, method, mapping);
            });
        }
    }
}

Let’s take a look at the acquisition of handler

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
    //Get matching processor
    @Override
    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        //Get the real path part
        String lookupPath = initLookupPath(request);

        // ...  Code omission

        try {
            //Method processor for obtaining path matching
            HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
            //If the handlermethod bean is a string, use it as a bean name to get the bean instance
            return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
        }
        finally {
            // ...  Code omission
        }
    }

    //Method processor for obtaining path matching
    protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
        List<Match> matches = new ArrayList<>();

        //Direct match path
        List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
        //Directly matched to path
        if (directPathMatches != null) {
            //Add matching mapping to matches
            addMatchingMappings(directPathMatches, matches, request);
        }
        //If there is no direct match to path
        if (matches.isEmpty()) {
            //Match all the registration patterns
            addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
        }
        //It matches
        if (!matches.isEmpty()) {
            //The first match is taken by default
            Match bestMatch = matches.get(0);
            if (matches.size() > 1) {
                //If multiple patterns are matched, they are sorted and the best one is selected
                Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
                matches.sort(comparator);
                bestMatch = matches.get(0);

                // ...  Code omission
            }

            // ...  Code omission

            return bestMatch.handlerMethod;
        }
        else {
            //No match found, null returned
            return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
        }
    }
}

The registration and management of processors are actually internal classesRequestMappingHandlerMapping.MappingRegistry
Completed

class MappingRegistry {
    //Processor registration container
    private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
    //Path lookup container
    private final MultiValueMap<String, T> pathLookup = new LinkedMultiValueMap<>();
    //Name lookup container
    private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();

    //Register a processor
    public void register(T mapping, Object handler, Method method) {
        try {
            //Package is handlermethod
            HandlerMethod handlerMethod = createHandlerMethod(handler, method);

            //Get non pattern matching path
            Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
            for (String path : directPaths) {
                //Add to path lookup container
                this.pathLookup.add(path, mapping);
            }

            String name = null;
            if (getNamingStrategy() != null) {
                //Get bean name
                name = getNamingStrategy().getName(handlerMethod, mapping);
                //Add to name lookup container
                addMappingName(name, handlerMethod);
            }

            // ...  Code omission

            //Add to processor registration container
            this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directPaths, name));
        }
        finally {
            // ...  Code omission
        }
    }
}

2.2. RequestMappingInfoHandlerMapping

RequestMappingInfoHandlerMapping
The main function of is to realize the mapping from request to handlermethod through requestmappinginfo

public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> {
    //Check whether the request matches the path mapping
    @Override
    protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
        super.handleMatch(info, lookupPath, request);

        //Get conditions for pattern matching
        RequestCondition<?> condition = info.getActivePatternsCondition();
        //If the path matches, wildcards will be resolved, such as *?
        if (condition instanceof PathPatternsRequestCondition) {
            extractMatchDetails1((PathPatternsRequestCondition) condition, lookupPath, request);
        }
        //Normal string matching
        else {
            extractMatchDetails2((PatternsRequestCondition) condition, lookupPath, request);
        }

        // ...  Code omission
    }

    //If the path matches, wildcards will be resolved, such as *?
    private void extractMatchDetails1(
            PathPatternsRequestCondition condition, String lookupPath, HttpServletRequest request) {
        //Best match
        PathPattern bestPattern;
        //Uri variable, such as / path /: userid /: page
        Map<String, String> uriVariables;

        //Match to empty string ''
        if (condition.isEmptyPathMapping()) {
            bestPattern = condition.getFirstPattern();
            uriVariables = Collections.emptyMap();
        }
        else {
            PathContainer path = ServletRequestPathUtils.getParsedRequestPath(request).pathWithinApplication();
            bestPattern = condition.getFirstPattern();
            //Pathpattern parses matches and extracts variables (pathpattern is an enhanced version of ant pathmatcher)
            PathPattern.PathMatchInfo result = bestPattern.matchAndExtract(path);

            uriVariables = result.getUriVariables();

            // ...  Code omission
        }

        // ...  Code omission
    }

    //Normal string matching
    private void extractMatchDetails2(
            PatternsRequestCondition condition, String lookupPath, HttpServletRequest request) {
        //Best match
        PathPattern bestPattern;
        //Uri variable, such as / path /: userid /: page
        Map<String, String> uriVariables;

        //Match to empty string ''
        if (condition.isEmptyPathMapping()) {
            bestPattern = lookupPath;
            uriVariables = Collections.emptyMap();
        }
        else {
            bestPattern = condition.getPatterns().iterator().next();
            //Antpathmatcher parses the match and extracts variables
            uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath);
            uriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables);
        }

        // ...  Code omission
    }
}

2.3. RequestMappingHandlerMapping

RequestMappingHandlerMapping
The main function of is to realize@RequestMappingAnd@ControllerAnnotated processor mapping registration

public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
        implements MatchableHandlerMapping, EmbeddedValueResolverAware {
    //Get mapping information of method
    @Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        RequestMappingInfo info = createRequestMappingInfo(method);
        if (info != null) {
            RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
            if (typeInfo != null) {
                info = typeInfo.combine(info);
            }
            String prefix = getPathPrefix(handlerType);
            if (prefix != null) {
                info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
            }
        }
        return info;
    }

    //Create mapping information object
    private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
        //Find @ requestmapping annotation
        RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);

        // ...  Code omission

        return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
    }

    //Create a mapping information object according to requestmapping
    protected RequestMappingInfo createRequestMappingInfo(
            RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {

        RequestMappingInfo.Builder builder = RequestMappingInfo
                //Path meta information
                .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
                //Method meta information
                .methods(requestMapping.method())
                //Params meta information
                .params(requestMapping.params())
                //Headers meta information
                .headers(requestMapping.headers())
                //Consumers meta information
                .consumes(requestMapping.consumes())
                //Produces meta information
                .produces(requestMapping.produces())
                //Name meta information
                .mappingName(requestMapping.name());
        if (customCondition != null) {
            builder.customCondition(customCondition);
        }
        return builder.options(this.config).build();
    }
}

3. RouterFunctionMapping

RouterFunctionMapping
The main function of is to realizeRouterFunction
Support, useRouterFunctions.routeTo define routes, such as

@Configuration
public class MyRoutes {
    @Bean
    RouterFunction<ServerResponse> home() {
        return route(GET("/"), request -> ok().body(fromObject("Home page")));
    }

    @Bean
    RouterFunction<ServerResponse> about() {
        return route(GET("/about"), request -> ok().body(fromObject("About page")));
    }
}

RouterFunctionMappingThe inheritance relationship is as follows

- AbstractHandlerMapping
  - RouterFunctionMapping
public class RouterFunctionMapping extends AbstractHandlerMapping implements InitializingBean {
    //When all attributes are injected, this method is called by the context environment for initialization
    @Override
    public void afterPropertiesSet() throws Exception {
        if (this.routerFunction == null) {
            //Initialize routerfunction
            initRouterFunction();
        }

        // ...  Code omission
    }

    //Initialize routerfunction
    private void initRouterFunction() {
        ApplicationContext applicationContext = obtainApplicationContext();
        //Get the bean of routerfunction
        Map<String, RouterFunction> beans =
                (this.detectHandlerFunctionsInAncestorContexts ?
                        BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RouterFunction.class) :
                        applicationContext.getBeansOfType(RouterFunction.class));

        List<RouterFunction> routerFunctions = new ArrayList<>(beans.values());

        //Combine these beans
        this.routerFunction = routerFunctions.stream()
                .reduce(RouterFunction::andOther)
                .orElse(null);
    }

    //Get matching processor
    @Override
    protected Object getHandlerInternal(HttpServletRequest servletRequest) throws Exception {
        if (this.routerFunction != null) {
            ServerRequest request = ServerRequest.create(servletRequest, this.messageConverters);
            setAttributes(servletRequest, request);

            //Use routerfunction to route the request. If there is no, null will be returned
            return this.routerFunction.route(request).orElse(null);
        }
        else {
            return null;
        }
    }
}

4. RequestMappingHandlerAdapter

HttpRequestHandlerAdapterAndSimpleControllerHandlerAdapterThe strategy is relatively simple, so it will not be analyzed here

RequestMappingHandlerAdapter
The main function of is to support@RequestMappingDefine routing adaptation calls

The inheritance relationship is as follows

- WebContentGenerator
  - AbstractHandlerMethodAdapter
    - RequestMappingHandlerAdapter

WebContentGenerator
The main function of is to process the header information of the response, such asPragmaExpiresCache-Controletc.

AbstractHandlerMethodAdapter
The main function of is to support responseHandlerMethod

public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
    //Call the processor to respond to the request
    public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        return handleInternal(request, response, (HandlerMethod) handler);
    }

    //Call the processor to respond to the request,子类实现
    protected abstract ModelAndView handleInternal(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;
}

Now let’s seeRequestMappingHandlerAdapter

4.1. RequestMappingHandlerAdapter.afterPropertiesSet

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
        implements BeanFactoryAware, InitializingBean {
    //When all attributes are injected, this method is called by the context environment for initialization
    @Override
    public void afterPropertiesSet() {
        //Initialize the component marked with ` @ controlleradvice 'annotation
        initControllerAdviceCache();

        if (this.argumentResolvers == null) {
            //Get the default parameter parser
            List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
            this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }
        if (this.initBinderArgumentResolvers == null) {
            //Get the default @ initbinder parser
            List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
            this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }
        if (this.returnValueHandlers == null) {
            //Gets the default response value processor
            List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
            this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
        }
    }

    //Initialize the component marked with ` @ controlleradvice 'annotation
    private void initControllerAdviceCache() {
        // ...  Code omission

        //Get the bean with ` @ controlleradvice 'annotation
        List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
        //Available beans
        List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();
        //Traverse
        for (ControllerAdviceBean adviceBean : adviceBeans) {
            Class<?> beanType = adviceBean.getBeanType();
            if (beanType == null) {
                //No type, error reported
            }
            //Find methods annotated with ` @ requestmapping 'and ` @ modelattribute'
            Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
            if (!attrMethods.isEmpty()) {
                //Add to container
                this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
            }
            //Find the method with ` @ initbinder 'annotation
            Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
            if (!binderMethods.isEmpty()) {
                //Add to container
                this.initBinderAdviceCache.put(adviceBean, binderMethods);
            }
            //How can the bean type be a subclass of requestbodyadvice or responsebodyadvice
            if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
                //Add to container
                requestResponseBodyAdviceBeans.add(adviceBean);
            }
        }

        if (!requestResponseBodyAdviceBeans.isEmpty()) {
            //Add to container
            this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
        }

        // ...  Code omission
    }
}
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
        implements BeanFactoryAware, InitializingBean {
    //Get the default parameter parser
    private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
        List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);

        //@ requestparam resolution
        resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
        resolvers.add(new RequestParamMapMethodArgumentResolver());
        //@ pathvariable parsing
        resolvers.add(new PathVariableMethodArgumentResolver());
        resolvers.add(new PathVariableMapMethodArgumentResolver());
        //@ matrixvariable parsing
        resolvers.add(new MatrixVariableMethodArgumentResolver());
        resolvers.add(new MatrixVariableMapMethodArgumentResolver());
        //Data binding analysis
        resolvers.add(new ServletModelAttributeMethodProcessor(false));
        //@ requestbody @ ResponseBody parsing
        resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
        //@ requestpart resolution
        resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
        //@ requestheader parsing
        resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
        resolvers.add(new RequestHeaderMapMethodArgumentResolver());
        //Cookie parsing
        resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
        //@ value parse
        resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
        //@ sessionattribute resolution
        resolvers.add(new SessionAttributeMethodArgumentResolver());
        //@ requestattribute resolution
        resolvers.add(new RequestAttributeMethodArgumentResolver());

        //Parse the request header, request body, etc. from the input stream of the native ServletRequest object
        resolvers.add(new ServletRequestMethodArgumentResolver());
        //Write the final data of the processor into the output stream of the native servletresponse object, including response header, response body, etc
        resolvers.add(new ServletResponseMethodArgumentResolver());
        //Httpentity processing
        resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
        //Redirection processing
        resolvers.add(new RedirectAttributesMethodArgumentResolver());
        //Model processing
        resolvers.add(new ModelMethodProcessor());
        //Map processing
        resolvers.add(new MapMethodProcessor());
        //Error method analysis
        resolvers.add(new ErrorsMethodArgumentResolver());
        //Sessionstatus parsing
        resolvers.add(new SessionStatusMethodArgumentResolver());
        //Uricomponentsbuilder parsing
        resolvers.add(new UriComponentsBuilderMethodArgumentResolver());

        // ...  Code omission

        return resolvers;
    }

    //Get the default @ initbinder parser
    private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
        List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(20);

        resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
        resolvers.add(new RequestParamMapMethodArgumentResolver());
        resolvers.add(new PathVariableMethodArgumentResolver());
        resolvers.add(new PathVariableMapMethodArgumentResolver());
        resolvers.add(new MatrixVariableMethodArgumentResolver());
        resolvers.add(new MatrixVariableMapMethodArgumentResolver());
        resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
        resolvers.add(new SessionAttributeMethodArgumentResolver());
        resolvers.add(new RequestAttributeMethodArgumentResolver());

        resolvers.add(new ServletRequestMethodArgumentResolver());
        resolvers.add(new ServletResponseMethodArgumentResolver());

        // ...  Code omission

        return resolvers;
    }
}
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
        implements BeanFactoryAware, InitializingBean {
    //Gets the default response value processor
    private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
        List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(20);

        //Modelandview processing
        handlers.add(new ModelAndViewMethodReturnValueHandler());
        //Model processing
        handlers.add(new ModelMethodProcessor());
        //View processing
        handlers.add(new ViewMethodReturnValueHandler());
        //Responsebodyemitter processing
        handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
                this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
        //Streamingresponsebody processing
        handlers.add(new StreamingResponseBodyReturnValueHandler());
        //Httpentity processing
        handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
                this.contentNegotiationManager, this.requestResponseBodyAdvice));
        //Httpheaders processing
        handlers.add(new HttpHeadersReturnValueHandler());
        //Callable processing
        handlers.add(new CallableMethodReturnValueHandler());
        //Eddef processing
        handlers.add(new DeferredResultMethodReturnValueHandler());
        //Webasynctask processing
        handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));

        //Data binding analysis
        handlers.add(new ServletModelAttributeMethodProcessor(false));
        //@ requestbody @ ResponseBody parsing
        handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
                this.contentNegotiationManager, this.requestResponseBodyAdvice));

        //View name processing
        handlers.add(new ViewNameMethodReturnValueHandler());
        //Map processing
        handlers.add(new MapMethodProcessor());

        // ...  Code omission

        return handlers;
    }
}

The parsers and processors above are inweb/servlet/mvc/method/annotation
Bao Heweb/method/annotation
Package, which will be analyzed later

4.2. RequestMappingHandlerAdapter.handleInternal

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
        implements BeanFactoryAware, InitializingBean {
    //Call the processor to respond to the request
    @Override
    protected ModelAndView handleInternal(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        //The response object may be view, data or view data binding
        ModelAndView mav;

        // ...  Code omission

        //Call processor
        mav = invokeHandlerMethod(request, response, handlerMethod);

        // ...  Code omission

        return mav;
    }

    //Call processor
    protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        //Request object
        ServletWebRequest webRequest = new ServletWebRequest(request, response);
        try {
            //Process ` @ controlleradvice 'and ` @ initbinder', and inject parameter resolver argumentresolvers
            //Coupled with the data binding of the response model, a binding factory binderfactory is generated
            WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
            //Bind binderfactory to the model and inject parameter parser argumentresolvers
            //Generate a model factory modelfactory
            ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

            //Encapsulate into an object
            ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
            if (this.argumentResolvers != null) {
                //Injection parameter resolver argumentresolvers
                invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
            }
            if (this.returnValueHandlers != null) {
                //Injection response processing returnvaluehandlers
                invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
            }
            //Set data binding factory
            invocableMethod.setDataBinderFactory(binderFactory);

            // ...  Code omission

            //Response container
            ModelAndViewContainer mavContainer = new ModelAndViewContainer();
            //Initialize model and container
            modelFactory.initModel(webRequest, mavContainer, invocableMethod);

            // ...  Code omission

            //Call processor,获取处理结果,应用响应处理returnValueHandlers
            invocableMethod.invokeAndHandle(webRequest, mavContainer);

            // ...  Code omission

            //Get the final modelandview
            return getModelAndView(mavContainer, modelFactory, webRequest);
        }
        finally {
            //Mark current request as completed
            webRequest.requestCompleted();
        }
    }

    //Get the final modelandview
    private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
            ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
        //Update model factory data
        modelFactory.updateModel(webRequest, mavContainer);
        //If it has been processed, null is returned
        if (mavContainer.isRequestHandled()) {
            return null;
        }
        //Get model object
        ModelMap model = mavContainer.getModel();
        //Generate modelandview
        ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());

        // ...  Code omission

        //Process redirection
        if (model instanceof RedirectAttributes) {
            // ...  Code omission
        }
        return mav;
    }
}

5. HandlerFunctionAdapter

HandlerFunctionAdapter
The main function of is to realizeRouterFunction
Adaptive processing of

public class HandlerFunctionAdapter implements HandlerAdapter, Ordered {
    @Override
    public ModelAndView handle(HttpServletRequest servletRequest,
            HttpServletResponse servletResponse,
            Object handler) throws Exception {

        // ...  Code omission

        ServerRequest serverRequest = getServerRequest(servletRequest);
        ServerResponse serverResponse;

        // ...  Code omission

        //Directly call handlerfunction Handle method processing
        HandlerFunction<?> handlerFunction = (HandlerFunction<?>) handler;
        serverResponse = handlerFunction.handle(serverRequest);

        if (serverResponse != null) {
            //Write the response data directly into the output stream of the native servletresponse object
            return serverResponse.writeTo(servletRequest, servletResponse, new ServerRequestContext(serverRequest));
        }
        else {
            return null;
        }
    }
}

follow-up

More blogs, seehttps://github.com/senntyou/blogs

Author:Deep (@ senntyou)

Copyright notice: Free Reprint – non commercial – non derivative – keep signature(Creative sharing 3.0 License