Springmvc入门(十四)HandlerMapper源码分析--RequestMappingHandlerMapping的Hander的注册

RequestMappingHandlerMapping这个Handler我们用的特别多,因为配置url跟类毕竟比较繁琐。所以常使用@RequestMapping作为请求路径的注解的处理器。

RequestMappingHandlerMapping的结构示意图

与BeanNameUrlHandlerMapping和SimpleUrlHandlerMapping类似,都是AbstractHandlerMapping,从RequestMappingHandlerMapping的结构图,先看AbstractHandlerMethodMapping的结构,由一个内部类MappingRegistry,此类定义了一系列的Map,由registry,mappingLookup,urlLookup,nameLookup,corsLookup,先解释这些Map的作用。

urlLookup:保存了url与方法执行条件的映射,url为key,方法条件为value

nameLookup:保存了类名的所有大写字母加“#”加方法的名词

mappingLookup:保存的是方法的执行条件和方法

registry:以方法执行条件为key ,保留了url,方法,方法执行条件,以及类名的所有大写字母加“#”加方法的名词

corsLookup:跨境

 

AbstractHandlerMethodMapping实现了InitializingBean接口,即会执行初始化方法afterPropertiesSet,然后initHandlerMethods方法,initHandlerMethods跟AbstractUrlHandlerMapping的初始化方法一样,把ioc容器中所有的bean的名称获取,然后对名称进行筛选,符合条件则执行detectHandlerMethods方法进行注册,handlerMethodsInitialized为模板方法,由子类实现。

    public void afterPropertiesSet() {
		initHandlerMethods();
	}
    protected void initHandlerMethods() {
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for request mappings in application context: " + getApplicationContext());
		}
		//获取bean的名词
		String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
				obtainApplicationContext().getBeanNamesForType(Object.class));
		//筛选bean
		for (String beanName : beanNames) {
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
				Class<?> beanType = null;
				try {
					beanType = obtainApplicationContext().getType(beanName);
				}
				catch (Throwable ex) {
					if (logger.isDebugEnabled()) {
						logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
					}
				}
				if (beanType != null && isHandler(beanType)) {
					detectHandlerMethods(beanName);
				}
			}
		}
		handlerMethodsInitialized(getHandlerMethods());
	}
protected void detectHandlerMethods(final Object handler) {
		//获取handler的类
		Class<?> handlerType = (handler instanceof String ?
				obtainApplicationContext().getType((String) handler) : handler.getClass());
	
		if (handlerType != null) {
			final Class<?> userType = ClassUtils.getUserClass(handlerType);
			//将methods与该方法的使用条件进行映射,比如是只处理get请求,请求头需要什么等等条件
			Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
					(MethodIntrospector.MetadataLookup<T>) method -> {
						try {
                            //模板方法,由子类实现
							return getMappingForMethod(method, userType);
						}
						catch (Throwable ex) {
							throw new IllegalStateException("Invalid mapping on handler class [" +
									userType.getName() + "]: " + method, ex);
						}
					});
			if (logger.isDebugEnabled()) {
				logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
			}
            //遍历
			methods.forEach((method, mapping) -> {
				Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
				//对方法进行注册
				registerHandlerMethod(handler, invocableMethod, mapping);
			});
		}
	}
	
	protected void registerHandlerMethod(Object handler, Method method, T mapping) {
		this.mappingRegistry.register(mapping, handler, method);
	}
	
	public void register(T mapping, Object handler, Method method) {
			//加锁
			this.readWriteLock.writeLock().lock();
			try {
				
				HandlerMethod handlerMethod = createHandlerMethod(handler, method);
				assertUniqueMethodMapping(handlerMethod, mapping);

				if (logger.isInfoEnabled()) {
					logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
				}
				//将请求条件 --> 方法进行映射放入mappingLookup的Map中
				this.mappingLookup.put(mapping, handlerMethod);

				List<String> directUrls = getDirectUrls(mapping);
				for (String url : directUrls) {
				//urlLookup是MultiValueMap这类型的Map,这个类型的map是key--> List,即一对多的关系
					this.urlLookup.add(url, mapping);
				}
				//将类名+#+方法名  与方法进行映射,放入nameLookup
				String name = null;
				if (getNamingStrategy() != null) {
					name = getNamingStrategy().getName(handlerMethod, mapping);
					addMappingName(name, handlerMethod);
				}

				CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
				if (corsConfig != null) {
					//跨境cors
					this.corsLookup.put(handlerMethod, corsConfig);
				}
				//请求条件,请求条件--》与请求路径,方法映射,类名+#+方法名 以及处理的url作为一个对象放入registry这个Map中
				this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
			}
			finally {
				//释放锁
				this.readWriteLock.writeLock().unlock();
			}
		}

RequestMappingHandlerMapping实现getMappingForMethod,主要是创建方法的条件以及是否是@RequestMapping注解。

    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);
			}
		}
		return info;
	}
	private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
		//找到@RequestMapping注解修饰的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);
	}
	

RequestMappingInfoHandlerMapping不参与请求注册,它只是后续匹配http请求以及父类中的Map的请求条件的Map进行校验。

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值