Back to Javatutorial

RequestMapping初始化流程

docs/Spring全家桶/SpringMVC源码分析/RequestMapping初始化流程.md

1.0.025.8 KB
Original Source

ǰУǷ DispatcherServlet ʼ̣Ľ RequestMapping ʼ̡˵ RequestMapping ʼֱ̣˵ spring @RequestMaping עĹ̡

1. ̸ @EnableWebMvc

spring mvc ֮ springmvc demo @EnableWebMvc ע һᵽspring ͨ @EnableWebMvc ע mvc ܣͨ @Import עΪĿ DelegatingWebMvcConfiguration.classͨ @Bean עķ spring mvc

  • public RequestMappingHandlerMapping requestMappingHandlerMapping(...)
  • public PathMatcher mvcPathMatcher()
  • public UrlPathHelper mvcUrlPathHelper()
  • ...

ôУ @RequestMaping עص RequestMappingHandlerMapping.

2. RequestMappingHandlerMapping#afterPropertiesSet

RequestMappingHandlerMapping Ǵ WebMvcConfigurationSupport У

@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping(
        @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
        @Qualifier("mvcConversionService") FormattingConversionService conversionService,
        @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {

    // bean
    RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
    mapping.setOrder(0);
    mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
    mapping.setContentNegotiationManager(contentNegotiationManager);
    mapping.setCorsConfigurations(getCorsConfigurations());

    // ãһƪᵽgetXxx()ȡ
    PathMatchConfigurer configurer = getPathMatchConfigurer();
    Boolean useSuffixPatternMatch = configurer.isUseSuffixPatternMatch();
    if (useSuffixPatternMatch != null) {
        mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
    }
    Boolean useRegisteredSuffixPatternMatch = configurer.isUseRegisteredSuffixPatternMatch();
    if (useRegisteredSuffixPatternMatch != null) {
        mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
    }
    Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
    if (useTrailingSlashMatch != null) {
        mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
    }
    UrlPathHelper pathHelper = configurer.getUrlPathHelper();
    if (pathHelper != null) {
        mapping.setUrlPathHelper(pathHelper);
    }
    PathMatcher pathMatcher = configurer.getPathMatcher();
    if (pathMatcher != null) {
        mapping.setPathMatcher(pathMatcher);
    }
    Map<String, Predicate<Class<?>>> pathPrefixes = configurer.getPathPrefixes();
    if (pathPrefixes != null) {
        mapping.setPathPrefixes(pathPrefixes);
    }

    return mapping;
}

// 
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
    return new RequestMappingHandlerMapping();
}

RequestMappingHandlerMapping ģǴһȻ˸ԡ󴴽󣬼 spring bean ڣ̶ RequestMappingHandlerMapping#afterPropertiesSet

@Override
public void afterPropertiesSet() {
    // һЩ
    this.config = new RequestMappingInfo.BuilderConfiguration();
    this.config.setUrlPathHelper(getUrlPathHelper());
    this.config.setPathMatcher(getPathMatcher());
    this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
    this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
    this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
    this.config.setContentNegotiationManager(getContentNegotiationManager());
    // øķ
    super.afterPropertiesSet();
}

һЩԣȻٵø afterPropertiesSet()׷ȥ

AbstractHandlerMethodMapping#afterPropertiesSet

@Override
public void afterPropertiesSet() {
    initHandlerMethods();
}

protected void initHandlerMethods() {
    // getCandidateBeanNames()ȡbeanbeanName
    // Ȼ󰤸 bean
    for (String beanName : getCandidateBeanNames()) {
        if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
            //  bean ¿
            processCandidateBean(beanName);
        }
    }
    // һ־ûʲô
    handlerMethodsInitialized(getHandlerMethods());
}

spring ڴʱȡ bean beanNameȻ beanName а AbstractHandlerMethodMapping#processCandidateBean

// beanľ߼
protected void processCandidateBean(String beanName) {
    // ȡ beanName Ӧ beanType
    // 1\. cglibbeanType Ϊ Xxx$$EnhancerBySpringCGLIB
    // 2\. jdk̬beanType Ϊ com.sum.proxy.$Proxy
    Class<?> beanType = null;
    try {
        beanType = obtainApplicationContext().getType(beanName);
    }
    catch (Throwable ex) {
        ...
    }
    // isHandler: beanTypeǷ @Controller  @RequestMapping ע
    if (beanType != null && isHandler(beanType)) {
        //  handlerMethods
        detectHandlerMethods(beanName);
    }
}

DZȽϼ򵥣Ҫǻȡ beanName Ӧ beanTypeȻжǷ @Controller/@RequestMapping ע⣬֮͵ AbstractHandlerMethodMapping#detectHandlerMethods һ

isHandler(Class) Ҫ˵£

  1. ʶ @Controllerͬʶ @RestControllerע @Controller ע⣬ʶע⣺

    //  @Controller
    @Controller
    // ʡע
    public @interface XxxController {
        ...
    }
    
    
  2. beanName Ӧ bean cglib beanbeanType Ϊ Xxx$$EnhancerBySpringCGLIBʶ丸 (ҲĿ) ϵ @Controller/@ReestMapping;

  3. beanName Ӧ bean jdk ̬ beanbeanType Ϊ com.sum.proxy.$Proxyʶ丸ӿϵ @Controller/@RequestMapping;

  4. beanType com.sum.proxy.$Proxy(jdk ̬)** ޷ʶĿϵ @Controller/@RequestMapping ** ģ

  5. ע @Controller/@RequestMapping Ҫʵ jdk ̬Ҫ @Controller/@RequestMapping ڽӿڼӿڵķϡ

AbstractHandlerMethodMapping#detectHandlerMethods beanType DZע @Controller/@RequestMapping ӿˡ

3. AbstractHandlerMethodMapping#detectHandlerMethods

AbstractHandlerMethodMapping#detectHandlerMethods ݣ

// handler
protected void detectHandlerMethods(Object handler) {
    Class<?> handlerType = (handler instanceof String ?
            obtainApplicationContext().getType((String) handler) : handler.getClass());
    if (handlerType != null) {
        // 1\. cglib󣬵õ丸࣬ҲĿ
        Class<?> userType = ClassUtils.getUserClass(handlerType);
        // 2\. ᴦ userTypeuserTypeIJObjectи༰ userType нӿڵķ
        Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
                // 3\. ÿ @RequestMapping򴴽 RequestMappingInfo
                //  @RequestMapping Ϣװö
                (MethodIntrospector.MetadataLookup<T>) method -> {
                    try {
                        // ﴦϵ @RequestMapping ע
                        return getMappingForMethod(method, userType);
                    }
                    catch (Throwable ex) {
                        ...
                    }
                });
        methods.forEach((method, mapping) -> {
            Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
            // 4\. ォhandlermappingmethod
            registerHandlerMethod(handler, invocableMethod, mapping);
        });
    }
}

¼£

  1. cglib 󣬵õ丸࣬ҲĿࣨΪֻ cglib 󣬶 jdk ̬أ isHandler(Class) ˵֪spring ʶ jdk ̬Ӧϵ @Controller/@RequestMapping ע⣬˲ִе
  2. userType``userType IJ Object и༰ userType нӿڵķ
  3. ÿ @RequestMapping򴴽 RequestMappingInfo @RequestMapping ϢװöУ
  4. עᣬ handler``mapping method 浽 Map С

3.1 ҷ

detectHandlerMethods ĴУ userType``userType иࣨ Object userType нӿڵķ£

MethodIntrospector#selectMethods(Class, MethodIntrospector.MetadataLookup)

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;
    // jdk̬
    if (!Proxy.isProxyClass(targetType)) {
        // cglib࣬ȡĸ class
        specificHandlerType = ClassUtils.getUserClass(targetType);
        handlerTypes.add(specificHandlerType);
    }
    // ȡнӿڣӿڵĸӿ.
    handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));
    for (Class<?> currentHandlerType : handlerTypes) {
        final Class<?> targetClass = (specificHandlerType != null 
                      ? specificHandlerType : currentHandlerType);
        // currentHandlerTypecurrentHandlerTypeIJObjectиࡢ
        // currentHandlerTypeнӿڵķ
        // aopʱõҲ
        ReflectionUtils.doWithMethods(currentHandlerType, method -> {
            Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
            T result = metadataLookup.inspect(specificMethod);
            if (result != null) {
                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
                if (bridgedMethod == specificMethod || 
                             metadataLookup.inspect(bridgedMethod) == null) {
                    methodMap.put(specificMethod, result);
                }
            }
        }, ReflectionUtils.USER_DECLARED_METHODS);
    }
    return methodMap;
}

3.2 RequestMappingInfo

ÿ @RequestMapping򴴽 RequestMappingInfo @RequestMapping ϢװöУ

RequestMappingHandlerMapping#getMappingForMethod

protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    // ϵ @RequestMapping
    RequestMappingInfo info = createRequestMappingInfo(method);
    if (info != null) {
        // ϵ @RequestMapping
        RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
        if (typeInfo != null) {
            // ϲϵ @RequestMapping 
            //  @RequestMapping("/test")ϵ @RequestMapping("/hello")
            // ϲĽΪ /test/hello
            info = typeInfo.combine(info);
        }
        String prefix = getPathPrefix(handlerType);
        if (prefix != null) {
            info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
        }
    }
    return info;
}

@Nullable
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
    // ȡ @RequestMapping ע
    RequestMapping requestMapping = AnnotatedElementUtils
            .findMergedAnnotation(element, RequestMapping.class);
    // ʵΪ
    RequestCondition<?> condition = (element instanceof Class ?
            getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
    return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}

//  RequestMappingInfo RequestMapping  @RequestMapping ע
protected RequestMappingInfo createRequestMappingInfo(
        RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {
    // ʵǽ @RequestMapping עװΪRequestMappingInfo
    RequestMappingInfo.Builder builder = RequestMappingInfo
            .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
            // Խ @RequestMapping ע
            .methods(requestMapping.method())
            .params(requestMapping.params())
            .headers(requestMapping.headers())
            .consumes(requestMapping.consumes())
            .produces(requestMapping.produces())
            .mappingName(requestMapping.name());
    if (customCondition != null) {
        builder.customCondition(customCondition);
    }
    return builder.options(this.config).build();
}

Ǿ @RequestMapping RequestMappingInfoת

RequestMappingInfo ʲô

public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {
    // ṩ˺ܶԣӦ @RequestMapping
    @Nullable
    private final String name;
    private final PatternsRequestCondition patternsCondition;
    private final RequestMethodsRequestCondition methodsCondition;
    private final ParamsRequestCondition paramsCondition;
    private final HeadersRequestCondition headersCondition;
    private final ConsumesRequestCondition consumesCondition;
    private final ProducesRequestCondition producesCondition;
    private final RequestConditionHolder customConditionHolder;

    // 췽
    public RequestMappingInfo(@Nullable String name, @Nullable PatternsRequestCondition patterns,
            @Nullable RequestMethodsRequestCondition methods, @Nullable ParamsRequestCondition params,
            @Nullable HeadersRequestCondition headers, @Nullable ConsumesRequestCondition consumes,
            @Nullable ProducesRequestCondition produces, @Nullable RequestCondition<?> custom) {

        this.name = (StringUtils.hasText(name) ? name : null);
        this.patternsCondition = (patterns != null ? patterns : new PatternsRequestCondition());
        this.methodsCondition = (methods != null ? methods : new RequestMethodsRequestCondition());
        this.paramsCondition = (params != null ? params : new ParamsRequestCondition());
        this.headersCondition = (headers != null ? headers : new HeadersRequestCondition());
        this.consumesCondition = (consumes != null ? consumes : new ConsumesRequestCondition());
        this.producesCondition = (produces != null ? produces : new ProducesRequestCondition());
        this.customConditionHolder = new RequestConditionHolder(custom);
    }

    // builder ģʽǰʹbuilderRequestMappingInfo
    private static class DefaultBuilder implements Builder {
        // ʡ
        ...

        //  ʹbuilder()
        @Override
        public RequestMappingInfo build() {
            ContentNegotiationManager manager = this.options.getContentNegotiationManager();
            PatternsRequestCondition patternsCondition = new PatternsRequestCondition(
                    this.paths, this.options.getUrlPathHelper(), this.options.getPathMatcher(),
                    this.options.useSuffixPatternMatch(), this.options.useTrailingSlashMatch(),
                    this.options.getFileExtensions());
            //  RequestMappingInfo 췽
            return new RequestMappingInfo(this.mappingName, patternsCondition,
                    new RequestMethodsRequestCondition(this.methods),
                    new ParamsRequestCondition(this.params),
                    new HeadersRequestCondition(this.headers),
                    new ConsumesRequestCondition(this.consumes, this.headers),
                    new ProducesRequestCondition(this.produces, this.headers, manager),
                    this.customCondition);
        }
    }
    // ʡ
    ...
}

3.3 ע

װ @RequestMapping Ϣ󣬽ǽӿϢעᵽ springmvc ˣ

RequestMappingHandlerMapping#registerHandlerMethod

@Override
protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
    // øķע߼
    super.registerHandlerMethod(handler, method, mapping);
    updateConsumesCondition(mapping, method);
}
//  @RequestBody ע
private void updateConsumesCondition(RequestMappingInfo info, Method method) {
    ConsumesRequestCondition condition = info.getConsumesCondition();
    if (!condition.isEmpty()) {
        for (Parameter parameter : method.getParameters()) {
            //   @RequestBody ע⣬ BodyRequired ֵ
            MergedAnnotation<RequestBody> annot = MergedAnnotations.from(parameter)
                    .get(RequestBody.class);
            if (annot.isPresent()) {
                condition.setBodyRequired(annot.getBoolean("required"));
                break;
            }
        }
    }
}

գ־ע߼ AbstractHandlerMethodMapping#registerHandlerMethod ɵģշˡڷǰһõ Map<Method, T> methods:

ԿӦ T RequestMappingInfo ˡ

3. AbstractHandlerMethodMapping#registerHandlerMethod

AbstractHandlerMethodMapping#registerHandlerMethod

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping 
        implements InitializingBean {

    protected void registerHandlerMethod(Object handler, Method method, T mapping) {
        this.mappingRegistry.register(mapping, handler, method);
    }

    // ʡ˺ö
    ... 

    class MappingRegistry {
        // Ϣȫmapmapping, handlerMethod, directUrls, nameϢ
        private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
        // е mapping map/test/hello/test/{name}
        private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
        // ȷurl map /test/hello
        private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();

        // ʡ˺ö
        ...

        public void register(T mapping, Object handler, Method method) {
            ...
            // ȡдд
            this.readWriteLock.writeLock().lock();
            try {
                // 1\. ȡ handlerMethodʵǽhandler  method װһ
                HandlerMethod handlerMethod = createHandlerMethod(handler, method);
                validateMethodMapping(handlerMethod, mapping);
                // 2\.  mappingLookup УΪ LinkedHashMap
                // springmvcһҪmap
                this.mappingLookup.put(mapping, handlerMethod);

                // 3\. ȡurlurlLookupΪMultiValueMapmap ͬһkeyжvalue
                // springmvcһҪmap
                List<String> directUrls = getDirectUrls(mapping);
                for (String url : directUrls) {
                    this.urlLookup.add(url, mapping);
                }
                String name = null;
                if (getNamingStrategy() != null) {
                    name = getNamingStrategy().getName(handlerMethod, mapping);
                    addMappingName(name, handlerMethod);
                }
                CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
                if (corsConfig != null) {
                    this.corsLookup.put(handlerMethod, corsConfig);
                }

                // 4\. mapping, handlerMethod, directUrls, nameȷװregistry
                // registry ΪHashMapspringmvc нӿϢȫһmap
                this.registry.put(mapping, new MappingRegistration<>(mapping, 
                        handlerMethod, directUrls, name));
            }
            finally {
                this.readWriteLock.writeLock().unlock();
            }
        }
    }
}

Կע߼ AbstractHandlerMethodMapping.MappingRegistry#register ɵġǾһע߼

3.1 ȡ HandlerMethod

ش£

protected HandlerMethod createHandlerMethod(Object handler, Method method) {
    if (handler instanceof String) {
        return new HandlerMethod((String) handler,
                obtainApplicationContext().getAutowireCapableBeanFactory(), method);
    }
    return new HandlerMethod(handler, method);
}

ηǼ򵥵ص HandlerMethod Ĺ췽

public class HandlerMethod {

    // ṩ˷dz
    protected final Log logger = LogFactory.getLog(getClass());
    private final Object bean;
    @Nullable
    private final BeanFactory beanFactory;
    private final Class<?> beanType;
    private final Method method;
    private final Method bridgedMethod;
    private final MethodParameter[] parameters;
    @Nullable
    private HttpStatus responseStatus;
    @Nullable
    private String responseStatusReason;
    @Nullable
    private HandlerMethod resolvedFromHandlerMethod;
    @Nullable
    private volatile List<Annotation[][]> interfaceParameterAnnotations;
    private final String description;

    // 췽
    public HandlerMethod(Object bean, Method method) {
        Assert.notNull(bean, "Bean is required");
        Assert.notNull(method, "Method is required");
        this.bean = bean;
        this.beanFactory = null;
        this.beanType = ClassUtils.getUserClass(bean);
        this.method = method;
        this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
        this.parameters = initMethodParameters();
        evaluateResponseStatus();
        this.description = initDescription(this.beanType, this.method);
    }

    // ʡ
    ...
}

ԿHandlerMethod зdzԣ췽ҲǸֵѡɴ˿ɿHandlerMethod Ƕ handler method һװ

3.2 ֤ mapping Ƿظ

springmvc ʹУСĶͬ requestMapping

Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 
'xxxController' method xxxMethod to /xxx/xxx: There is already 'xxxControllter' 
bean method xxxMethod mapped.

쳣֤ mapping ʱظ mapping ģ£

// е mapping map/test/hello/test/{name}
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();

private void validateMethodMapping(HandlerMethod handlerMethod, T mapping) {
    // ҵѴڵ method
    HandlerMethod existingHandlerMethod = this.mappingLookup.get(mapping);
    // ѴڵhandlerMethodΪգҲڵǰ handlerMethod
    if (existingHandlerMethod != null && !existingHandlerMethod.equals(handlerMethod)) {
        throw new IllegalStateException(
                "Ambiguous mapping. Cannot map '" + handlerMethod.getBean() + "' method \n" +
                handlerMethod + "\nto " + mapping + ": There is already '" +
                existingHandlerMethod.getBean() + "' bean method\n" +
                existingHandlerMethod + " mapped.");
    }
}

Ǹ mapping mappingLookup в HandlerMethodҵҵ handlerMethod ǵǰ handlerMethodʾظͱ쳣ˡ

ֱж HandlerMethod RequestMappingInfo жȵģ

HandlerMethod#equals

@Override
public boolean equals(@Nullable Object other) {
    if (this == other) {
        return true;
    }
    if (!(other instanceof HandlerMethod)) {
        return false;
    }
    HandlerMethod otherMethod = (HandlerMethod) other;
    return (this.bean.equals(otherMethod.bean) && this.method.equals(otherMethod.method));
}

RequestMappingInfo#equals

@Override
public boolean equals(@Nullable Object other) {
    if (this == other) {
        return true;
    }
    if (!(other instanceof RequestMappingInfo)) {
        return false;
    }
    RequestMappingInfo otherInfo = (RequestMappingInfo) other;
    return (this.patternsCondition.equals(otherInfo.patternsCondition) &&
            this.methodsCondition.equals(otherInfo.methodsCondition) &&
            this.paramsCondition.equals(otherInfo.paramsCondition) &&
            this.headersCondition.equals(otherInfo.headersCondition) &&
            this.consumesCondition.equals(otherInfo.consumesCondition) &&
            this.producesCondition.equals(otherInfo.producesCondition) &&
            this.customConditionHolder.equals(otherInfo.customConditionHolder));
}

RequestMappingInfo Ҫͬжȣ @RequestMappingõ RequestMappingInfo ȣ

//  @RequestMappingȻ·ǡ/helloֵ֧󷽷ͬ
// ˵õ RequestMappingInfo 

@RequestMapping(path = "/hello")
public String hello1() {
    ...
}

@RequestMapping(path = "/hello", method = RequestMethod.GET)
public String hello2() {
    ...
}

@RequestMapping(path = "/hello", method = RequestMethod.POST)
public String hello3() {
    ...
}

3.3 ȡ directUrls

springmvc У url :

  1. ȷ url

    @RequestMapping("/hello")
    public String hello() {
       ...
    }
    
    
  2. ȷ url

    @RequestMapping("/{name}")
    public String hello(@PathVariable("name") String name) {
       ...
    }
    
    

springmvc ṩרŵ urlLookup ȷ urlṹ£

MultiValueMap<String, LinkedList<RequestMappingInfo>>

springmvc λȡȷ url :

List<String> directUrls = getDirectUrls(mapping);

/**
 * AbstractHandlerMethodMapping.MappingRegistry#getDirectUrls
 * ȡȷurl
 */
private List<String> getDirectUrls(T mapping) {
    List<String> urls = new ArrayList<>(1);
    // RequestMappingInfoȡе MappingPathPattern
    for (String path : getMappingPathPatterns(mapping)) {
        // жϵõ MappingPathPattern ǷΪȷurl
        if (!getPathMatcher().isPattern(path)) {
            urls.add(path);
        }
    }
    return urls;
}

/**
 * RequestMappingInfoHandlerMapping#getMappingPathPatterns
 * ȡ patterns,  RequestMappingInfo ȡ
 * ʵϾ @RequestMapping е path() ֵ
 */
@Override
protected Set<String> getMappingPathPatterns(RequestMappingInfo info) {
    return info.getPatternsCondition().getPatterns();
}

/**
 * AntPathMatcher#isPattern
 * жǷΪȷ url
 * ֻҪ *֮һͬʱ{}Ͳȷurl
 */
@Override
public boolean isPattern(@Nullable String path) {
    if (path == null) {
        return false;
    }
    boolean uriVar = false;
    for (int i = 0; i < path.length(); i++) {
        char c = path.charAt(i);
        if (c == '*' || c == '?') {
            return true;
        }
        if (c == '{') {
            uriVar = true;
            continue;
        }
        if (c == '}' && uriVar) {
            return true;
        }
    }
    return false;
}

£

  1. ȡǰ mapping pathҲ @RequestMapping path() ֵ
  2. õ pathһжǷΪȷ url (ֻҪ *``? ֮һͬʱ {``}Ͳȷ url).

3.4 עӿϢ

עӿϢͱȽϼˣʵ map ݣ map

  • urlLookupȷ url mapΪ MultiValueMap<String, LinkedList<RequestMappingInfo>>``key Ϊȷ url /test/hello``value Ϊ LinkedList<RequestMappingInfo>

  • mappingLookupе mapping mapе @RequestMapping Ӧ RequestMappingInfo ҵ /test/hello``/test/{name} Ӧ RequestMappingInfoΪ Map<RequestMappingInfo, HandlerMethod>

  • registryϢȫ mapΪ Map<RequestMappingInfo, MappingRegistration<RequestMappingInfo>>е RequestMappingInfokey Ϊ RequestMappingInfovalue Ϊ MappingRegistration<RequestMappingInfo> MappingRegistration Ϊ mapping, handlerMethod, directUrls, name İװ࣬Ҳ˵ MappingRegistration mapping, handlerMethod, directUrls, name Ϣ

Щ map ע൱ˣǼ򵥵ص Map#put Ͳ˵ˡ

4. ܽ

ķ spring @RequestMapping ע̣ⲿ RequestMappingHandlerMapping#afterPropertiesSet У£

  1. ȡ bean beanName 2
  2. ҵ beanName Ӧ beanTypeжǷ @Controller/@RequestMapping ע⣻
  3. ԰ @Controller/@RequestMapping beanTypeҵ @RequestMapping עķ @RequestMapping עװΪ RequestMappingInfoһõĽΪһ mapMap<Method, RequestMappingInfo>
  4. beanName``beanType Map<Method, RequestMappingInfo> עᵽ springmvc УȽҪ map
  • MultiValueMap<String, LinkedList<RequestMappingInfo>>
  • Map<RequestMappingInfo, HandlerMethod>(HandlerMethod Ϊ Method İװ)
  • Map<RequestMappingInfo, MappingRegistration<RequestMappingInfo>>(MappingRegistration Ϊ RequestMappingInfo, HandlerMethod, directUrls, beanName İװ)

ܵ˵RequestMapping ĴرȽҲǵ˺öβҵ


ԭӣhttps://my.oschina.net/funcy/blog/4715079 ߸ˮƽд֮ӭָԭףҵתϵ߻Ȩҵתע