springmvc中RequestMappingHandlerMapping在tomcat启动时初始化过程释义浅见

本文详细解析了SpringMVC中RequestMappingHandlerMapping在Tomcat启动时的初始化过程,包括afterPropertiesSet()方法的调用,handlerMethods和urlMap的填充方式,以及isHandler和detectHandlerMethods方法的作用。在DispatcherServlet启动时,HandlerMapping按照Ordered接口定义的顺序排序,RequestMappingHandlerMapping由于order为0,故优先处理请求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

RequestMappingHandlerMapping实现了InitializingBean接口,所以在实例化时会执行afterPropertiesSet()方法,源码如下:

@Override
	public void afterPropertiesSet() {//requestMappingHandlerMapping类中方法
		if (this.useRegisteredSuffixPatternMatch) {
			this.fileExtensions.addAll(this.contentNegotiationManager.getAllFileExtensions());
		}
		super.afterPropertiesSet();//调用父类方法
	}

super.afterPropertiesSet();此行代码调用父类AbstractHandlerMethodMapping中的如下代码,源码如下:

public void afterPropertiesSet() {
		initHandlerMethods();
	}

本类中initHandlerMethods();方法源码如下:

protected void initHandlerMethods() {
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for request mappings in application context: " + getApplicationContext());
		}

		String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
				getApplicationContext().getBeanNamesForType(Object.class));

		for (String beanName : beanNames) {
			if (isHandler(getApplicationContext().getType(beanName))){
				detectHandlerMethods(beanName);//侦查洞测HandlerMethods
			}
		}
		handlerMethodsInitialized(getHandlerMethods());
	}

如上代码释义:先获取所有的beanNames,然后根据beanNames循环遍历,如果isHandler(getApplicationContext().getType(beanName))方法为真执行detectHandlerMethods(beanName);

isHandler方法释义源码如下:

@Override
	protected boolean isHandler(Class<?> beanType) {
		return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) ||
				(AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null));
	}//表示bean上是否有Controller注解或RequestMapping注解,通过此俩注解表示此bean是否处理器bean

detectHandlerMethods(beanName);方法源码如下:

	protected void detectHandlerMethods(final Object handler) {
		Class<?> handlerType =
				(handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());

		// Avoid repeated calls to getMappingForMethod which would rebuild RequestMatchingInfo instances
		final Map<Method, T> mappings = new IdentityHashMap<Method, T>();//存放方法和对应的RequestMappingInfo,key为方法名称,value为RequestMappingInfo
		final Class<?> userType = ClassUtils.getUserClass(handlerType);

		Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
			public boolean matches(Method method) {
				T mapping = getMappingForMethod(method, userType);//为方法创造一个对应的requestMappingInfo类型的mapping
				if (mapping != null) {
					mappings.put(method, mapping);//以controller中的每个方法为key,以每个方法对应的requestMappingInfo为value,存入mappings中
					return true;
				}
				else {
					return false;
				}
			}
		});

		for (Method method : methods) {
			registerHandlerMethod(handler, method, mappings.get(method));
		}
	}

如上代码释义:handlerType指我们的controller类型的值,如 class com.travelzen.tops.front.controller.PromotionController。

userType也是值controller。selectMethods方法是把controller的每个方法遍历出来并为每个方法封装一个requestMappingInfo放进map中,

最后注册handlerMethod,执行for循环中的此行代码,registerHandlerMethod(handler, method, mappings.get(method));源码如下:

protected void registerHandlerMethod(Object handler, Method method, T mapping) {
		HandlerMethod newHandlerMethod = createHandlerMethod(handler, method);//以处理器controller和其中的方法创建一个HandlerMethod
		HandlerMethod oldHandlerMethod = this.handlerMethods.get(mapping);//已requestMappingInfo为参从handlerMethods中取出一个HandlerMethod
		if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) {
			throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean() +
					"' bean method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '" +
					oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped.");
		}

		this.handlerMethods.put(mapping, newHandlerMethod);//以requestMappingInfo为key,和其对应的HandlerMethod为value存入handlerMethods中,方便以后取用
		if (logger.isInfoEnabled()) {
			logger.info("Mapped \"" + mapping + "\" onto " + newHandlerMethod);
		}

		Set<String> patterns = getMappingPathPatterns(mapping);//以requestMappingInfo为参获取patterns,其值就是url链接的值的形式,就是requestMappingInfo的value属性值,如: /compute/update,有多个时就是复数集合
		for (String pattern : patterns) {
			if (!getPathMatcher().isPattern(pattern)) {
				this.urlMap.add(pattern, mapping);//循环遍历,如果pattern不存在符号*或?就放入urlMap中,其中pattern(pattern形如/compute/update)为key,mapping(例如 /compute/update对应requestMappingInfo)为value,方便以后取用
			}
		}
	}

到此RequestMappingHandlerMapping初始化过程就算完成了。不对之处还望指正。

另补充一个重要的信息:

DispatcherServlet在启动时会根据配置文件创建HandlerMapping,这些HandlerMapping都实现了Ordered接口,DispatcherServlet实例化所有的HandlerMapping后放到一个集合中,并根据order对HandlerMapping进行排序。DispatcherServlet在接受请求时会循环遍历有序的HandlerMapping集合,RequestMappingHandlerMapping的order是0,开始接收请求。所以会以RequestMappingHandlerMapping这个处理器映射来处理请求而不是别的处理器映射。

参考:https://www.cnblogs.com/BINGJJFLY/p/7452717.html

           https://my.oschina.net/zhangxufeng/blog/2177464

           https://blog.youkuaiyun.com/weixin_34216196/article/details/91260441

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值