SpringMvc的RequestMappingHandlerMapping初始化源码阅读

首先,我们在AnnotationDrivenBeanDefinitionParser中会实例化一个RequestMappingHandlerMapping实例,然后向Spring容器中注册这个实例。

查看其父类可知,实现了InitializingBean接口。所以在实例化后会调用afterPropertiesSet方法

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

由此可见这个方法是用来在实例化时探测handler方法

	/**
	 * Detects handler methods at initialization.
	 */
	public void afterPropertiesSet() {
		initHandlerMethods();
	}

扫描ApplicationContext中的bean,探测和注册handler method

	/**
	 * Scan beans in the ApplicationContext, detect and register handler methods.
	 * @see #isHandler(Class)
	 * @see #getMappingForMethod(Method, Class)
	 * @see #handlerMethodsInitialized(Map)
	 */
	protected void initHandlerMethods() {
//...根据BeanFactory中存放的Bean的类型,找到所有的注册Bean
		String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
				getApplicationContext().getBeanNamesForType(Object.class));

		for (String beanName : beanNames) {
//根据RequestMapping或者Controller注解判断是不是Handler
                        if (isHandler(getApplicationContext().getType(beanName))){
				detectHandlerMethods(beanName);//探测
			}
		}
		handlerMethodsInitialized(getHandlerMethods());
	}

根据Method上的RequestMapping注解查找一个Handler中的handler方法

	/**
	 * Look for handler methods in a handler.
	 * @param handler the bean name of a handler or a handler instance
	 */
	protected void detectHandlerMethods(final Object handler) {
		Class<?> handlerType = (handler instanceof String) ?//判定是不是字符串,是则根据根据字符串获得其对应的类名
				getApplicationContext().getType((String) handler) : handler.getClass();

		final Class<?> userType = ClassUtils.getUserClass(handlerType);//判定是不是自定义的
                //根据一个方法过滤器获得被RequestMapping注解标记的Method
		Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
			public boolean matches(Method method) {
				return getMappingForMethod(method, userType) != null;
			}
		});

		for (Method method : methods) {遍历这个method集合,所以可知,每一个Method都会有对应的MappingInfo与之对应
			T mapping = getMappingForMethod(method, userType);//根据Method和类获取MappingInfo
                        //将返回的RequestMappingInfo注册到RequestMappingHandlerMapping上
                        registerHandlerMethod(handler, method, mapping);
		}
	}

使用方法和类级别的注解去创建一个RequestMappingInfo

	protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
		RequestMappingInfo info = null;//寻找方法上的RequestMapping注解,返回RequestMapping注解
		RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
		if (methodAnnotation != null) {
			RequestCondition<?> methodCondition = getCustomMethodCondition(method);//一个空的实现
			info = createRequestMappingInfo(methodAnnotation, methodCondition);//创建一个RequestMappingInfo
			RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
			if (typeAnnotation != null) {//虚招类上的RequestMapping注解,如果有,则进行组合操作
				RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType);//空的实现
				info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info);//组合MethodInfo
			}
		}
		return info;//返回这个RequestMappingInfo
	}


需要详细对RequestMappingInfo这个类进行分析,特别是其combine方法和里面的几个重要的属性。

	protected RequestMappingInfo createRequestMappingInfo(RequestMapping annotation,
			RequestCondition<?> customCondition) {

		String[] patterns = resolveEmbeddedValuesInPatterns(annotation.value());
		return new RequestMappingInfo(
				new PatternsRequestCondition(patterns, getUrlPathHelper(), getPathMatcher(),
					this.useSuffixPatternMatch, this.useTrailingSlashMatch, this.fileExtensions),
				new RequestMethodsRequestCondition(annotation.method()),
				new ParamsRequestCondition(annotation.params()),
				new HeadersRequestCondition(annotation.headers()),
				new ConsumesRequestCondition(annotation.consumes(), annotation.headers()),
				new ProducesRequestCondition(annotation.produces(), annotation.headers(),
                                         getContentNegotiationManager()),
				customCondition);
	}

将返回的RequestMappingInfo注册到RequestMappingHandlerMapping上,其中两个重要的属性handlerMethods以及urlMap。使用HandlerMethod是可以理解的,因为在调用Method时肯定需要传入一个instance实例才行,而handler则对应这个实例。所以将这两个封装在一个对象里,方便传递。

	protected void registerHandlerMethod(Object handler, Method method, T mapping) {
		HandlerMethod newHandlerMethod = createHandlerMethod(handler, method);//方法内部直接new出一个HandlerMethod对象
                //handlerMethods用来存放RequestMappingInfo与HandlerMethod的键值对  ,         
                HandlerMethod oldHandlerMethod = handlerMethods.get(mapping);
                //如果本来就已经存在不相同的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.");
		}
                //将RequestMappingInfo与HandlerMethod放入handlerMethods属性中
		this.handlerMethods.put(mapping, newHandlerMethod);
		if (logger.isInfoEnabled()) {
			logger.info("Mapped \"" + mapping + "\" onto " + newHandlerMethod);
		}
                //从RequestMappingInfo中获得一个pattern集合,就是ReqeustMapping注解的value值。。
		Set<String> patterns = getMappingPathPatterns(mapping);
		for (String pattern : patterns) {
			if (!getPathMatcher().isPattern(pattern)) {
                //将这个pattern与RequestMappingInfo关联起来,以便以后根据url进行匹配找到MappingInfo,再根据MappingInfo找到HandlerMethod
                             this.urlMap.add(pattern, mapping);
			}
		}
	}
至此可以知道初始化RequestMappingHandlerMapping时是将所有用ReqeustMapping标记的类和方法包装在一个HandlerMethod中,然后将其与RequestMappingInfo进行配对,并存入RequestMappingHandlerMapping的handlerMethods中。将pattern与RequestMappingInfo进行配对,存入RequestMappingHandlerMapping的urlMap中。可以预测,在servlet提供服务时,会根据requestPath匹配对应的url,进而得到HandlerMethod,处理具体业务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值