RequestMappingHandlerMapping的初始化原理

class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
        extends AbstractHandlerMethodMapping<RequestMappingInfo>
        extends AbstractHandlerMapping implements InitializingBean {

    // 执行初始化逻辑
    public void afterPropertiesSet() {
        // 初始化HandlerMethods,就是Handler和Methods关系
        initHandlerMethods();{
            // 找出所有的Bean
            for (String beanName : getCandidateBeanNames(){
                                        obtainApplicationContext().getBeanNamesForType(Object.class)
                                    })
             {
                // private static final String SCOPED_TARGET_NAME_PREFIX = "scopedTarget.";
                // 是个自定义的Bean
                if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
                    // 对这个bean进行操作
                    processCandidateBean(beanName);{
                      Class<?> beanType = obtainApplicationContext().getType(beanName);
                      // 判断是否一个handler处理器
                      if (beanType != null && isHandler(beanType){
                                                      // 存在Controller.class注解,或者添加了RequestMapping注解(前提是个Bean才行)
                                                      return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
                                                      		 AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
                                              })
                      {
                            // 查找实际处理请求的方法,因为处理请求的方式有很多,可能是一个方法,也可能是一个实现了Servlet/Controller接口的类
                            detectHandlerMethods(beanName);{
                                // 找对对应的处理类
                                Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass());
                                // 找到真实的类型
                                Class<?> userType = ClassUtils.getUserClass(handlerType);{
                                    // 如果是Cglib代理类,获取实际类型
                                    if (clazz.getName().contains("$$")) { return clazz.getSuperclass(); }
                                    return clazz;
                                }
                                // 找到所有添加了RequestMapping的方法,并且使用Method对象作为Map的key,通过RequestMapping注解信息创建的RequestMappingInfo对象为Value
                                Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
                                    (MethodIntrospector.MetadataLookup<T>) method -> {
                                        // 找到所有的方法对象
                                        return getMappingForMethod(method, userType);{
                                            // 根据RequestMapping封装成RequestMappingInfo对象
                                            RequestMappingInfo info = createRequestMappingInfo(method);{
                                                // 找到有RequestMappingInfo注解,创建RequestMappingInfo对象
                                                RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
                                                	return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition){
                                                	                                    RequestMappingInfo.Builder builder = RequestMappingInfo
                                                                                                .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
                                                                                                .methods(requestMapping.method())...;
                                                                                     } : null);
                                            }
                                            if (info != null) {
                                                // 判断是否存在类注解
                                                RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
                                                // 如果存在,则需要和方法路径合并
                                                if (typeInfo != null) {
                                                    info = typeInfo.combine(info);
                                                }
                                                // getPathPrefix: 如果配置了通用URL前缀,可以通过webmvcConfigurer来配置
                                                // class A implements WebMvcConfigurer
                                                //      public void configurePathMatch(PathMatchConfigurer configurer) {
                                                //        这样,当满足后面这个条件的情况下,url会自动拼接前缀
                                                //        configurer.addPathPrefix("/api/v1", aClass -> aClass.isAssignableFrom(TestController.class));
                                                //      }
                                                // }
                                                // 注意: 这个前缀是和HandlerMapping绑定的,使用@EnableWebMvc注解,会导入@Import(DelegatingWebMvcConfiguration.class)类
                                                // DelegatingWebMvcConfiguration类会执行所有实现了WebMvcConfigurer接口的类的方法
                                                // DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport,而WebMvcConfigurationSupport会注册多个Bean
                                                // 其中包括3个HandlerMapping和多个RequestMappingHandlerAdapter
                                                // 其中RequestMappingHandlerMapping创建的过程中,就设置了一些属性,例如mapping.setPathPrefixes(pathConfig.getPathPrefixes());
                                                // 就是刚才在configurePathMatch添加的前缀就会赋值给HandlerMapping的前缀,这样请求就添加了统一前缀了
                                                // 具体的@EnableWebMvc原理在后面讲
                                                String prefix = getPathPrefix(handlerType);
                                                if (prefix != null) {
                                                    // 拼接路径
                                                    info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
                                                }
                                            }
                                            return info;
                                        }
                                    });
                                     // 将所有查找到的方法和url映射到注册到mappingRegistry中
                                     methods.forEach((method, mapping) -> {
                                        Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
                                        registerHandlerMethod(handler, invocableMethod, mapping);{
                                           // 将映射信息保存
                                           // MappingRegistry mappingRegistry = new MappingRegistry(){
                                           //   实际上,所有的url,method映射都是存在registry这里
                                           //   private final Map<T, MappingRegistration<T>> registry = new HashMap<>();{
                                           //       // MappingRegistration类的字段
                                           //       private final T mapping;
                                           //       private final HandlerMethod handlerMethod;
                                           //       private final Set<String> directPaths;
                                           // }
                                           //   为什么是多个值的map,因为restful支持相同的url和不同的请求方式,所以,url是同一个,RequestMappingInfo有多个
                                           //   private final MultiValueMap<String, T> pathLookup = new LinkedMultiValueMap<>();
                                           //   private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
                                           //   private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
                                           // }
                                           this.mappingRegistry.register(mapping, handler, method);{
                                                // 将handler和method封装成Handler对象
                                                HandlerMethod handlerMethod = createHandlerMethod(handler, method);{
                                                    if (handler instanceof String) {
                                                    	return new HandlerMethod((String) handler,beanFactory, method);
                                                    }
                                                    return new HandlerMethod(handler, method);
                                                }
                                                // 校验是否要相同url的method
                                                validateMethodMapping(handlerMethod, mapping);
                                                // 获取RequestMapping可以处理的路径,因为RequestMapping的value是可以数组,可以处理多个url
                                                Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
                                                // 保存到pathLookup中,pathLookup是存储了url->requestMappingInfo的映射
                                                // 也就是直接通过url找到对应的RequestMappingInfo,在通过RequestMappingInfo获取MappingRegistration对象,下面this.registry.put(mapping)几行有解释
                                                for (String path : directPaths) {
                                                    this.pathLookup.add(path, mapping);
                                                }
                                                // 初始化跨域配置
                                                CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
                                                // 将方法,bean,映射,url等信息包装成MappingRegistration对象,然后使用RequestMappingInfo作为Key
                                                // 这样请求来了可以通过pathLookup获取对对应的RequestMappingInfo,在从registry获取MappingRegistration,就可以执行方法了
                                                this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directPaths, name, corsConfig != null));
                                           }
                                        }
                                    });
                                }
                            }
                      }
                    }
                }
            }
            // 查询了所有的方法映射之后做的初始化操作,没有逻辑
            handlerMethodsInitialized(getHandlerMethods());
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值