spring 源码分析 管理请求映射-上 (RequestMappingHandlerMapping)

  • Post author:
  • Post category:其他




RequestMappingHandlerMapping 类结构

继承结构:
 RequestMappingHandlerMapping	  	impl实现    MatchableHandlerMapping接口、EmbeddedValueResolverAware接口
	--|RequestMappingInfoHandlerMapping	
		--|AbstractHandlerMethodMapping		impl实现   InitializingBean接口
			--|AbstractHandlerMapping		impl实现	   HandlerMapping接口、BeanNameAware接口、Ordered接口
				--|WebApplicationObjectSupport		impl实现    ServletContextAware接口
					--|ApplicationObjectSupport		impl实现	   ApplicationContextAware接口

RequestMappingHandlerMapping 是HandlerMapping接口的实现

interface HandlerMapping {
		HandlerExecutionChain  gethandler (HttpServletRequest  request);
}



注册bean过程:

spring 扩展机制, InitializingBean 接口 afterPropertiesSet() 方法:在类初始化完成调用此方法

AbstractHandlerMethodMapping 的 afterPropertiesSet() 方法

	//等对象初始化完成调用该方法
	public void afterPropertiesSet() {
		initHandlerMethods();
	}

	/**
	 * 初始 HandlerMethod
	 * 	1、获取所有Object 的 bean名称
	 * 	2、过滤掉 scopedTarget. 的bean名称
	 * 	3、通过bean名称得到bean类型, 储存包含@Controller @RequestMapping 注解的class
	 */
	protected void initHandlerMethods() {
		for (String beanName : getCandidateBeanNames()) {	//获取所有bean名称
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
				//如果该beanName, 不是scopedTarget.  处理bean
				//1、先获取该bean的class
				//2、通过class去判断是否含有@Controller @RequestMapping 注解
				//3、处理该class, 创建 RequestMappingInfo 对象.   ====>>>>  detectHandlerMethods()
				//4、把该class中的方法注册到 MappingRegistry 中.   ===>>>>  registerHandlerMethod()
				processCandidateBean(beanName);
			}
		}
		handlerMethodsInitialized(getHandlerMethods());
	}

	/**
	 * 确定指定的候选bean的类型,如果标识为Controller处理程序类,则调用{@link #detectHandlerMethods}。
	 */
	protected void processCandidateBean(String beanName) {
		Class<?> beanType = null;
		try {
			// 获取bean名称对应的class
			beanType = obtainApplicationContext().getType(beanName);
		}
		catch (Throwable ex) {
			if (logger.isTraceEnabled()) {
				logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
			}
		}
		if (beanType != null && isHandler(beanType)) {		//效验当前class是否 @Controller 类和 @RequestMapping类
			// 在对该class 做处理
			detectHandlerMethods(beanName); 	
		}
	}

	// 是否@Controller控制类
	@Override
	protected boolean isHandler(Class<?> beanType) {
		return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
				AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
	}

	/**
	 * 处理@Controller  @RequestMapping 处理的类beaName
	 */
	protected void detectHandlerMethods(Object handler) {
		Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass());

		if (handlerType != null) {
			//是否代理class
			Class<?> userType = ClassUtils.getUserClass(handlerType);
			//获取类中的所有 Method ==>> RequestMappingInfo
			Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
					(MethodIntrospector.MetadataLookup<T>) method -> {
						try {
							// 创建 RequestMappingInfo 对象为 @RequestMapping()注解中的信息
							return getMappingForMethod(method, userType);
						}
						catch (Throwable ex) {
							throw new IllegalStateException("Invalid mapping on handler", ex);
						}
					});
			if (logger.isTraceEnabled()) {
				logger.trace(formatMappings(userType, methods));
			}
			// 此时的mapping 键为 RequestMappingInfo
			methods.forEach((method, mapping) -> {
				Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
				// 通过该方法注册调用bean的信息
				registerHandlerMethod(handler, invocableMethod, mapping);
			});
		}
	}

这里看AbstractHandlerMethodMapping 类中一个属性对象 MappingRegistry (缓存池), 是一个内部类.主要用来储存对象信息.如:HandlerMethod(处理方法)、 RequestMappingInfo(请求路径)、 CorsConfiguration(跨域)

class MappingRegistry {

		//储存 MappingRegistration 所有的注册信息
		private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
		//储存RequestMappingInfo 与 HandlerMethod
		private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
		//储存路径与RequestMappingInfo
		private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
		//储存@RequestMapping 注解的请求路径 与 HandlerMethod列表
		private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
		//跨域配置
		private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
		//读写锁
		private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
		
		/**
		 * 注册数据:  mapping => RequestMappingInfo	||  handler => beanName  ||  method => Method
		 *  	1、创建 HandlerMethod, 根据 handle 和 method
		 * 		2、效验 HandlerMethod 是否存在
		 * 		3、储存 HandlerMethod
		 * 		4、储存 RequestMappingInfo 跟 url
		 * 		5、储存 @RequestMapping 注解 的路径跟所有的方法
		 * 		6、存储 CorsConfiguration 信息(跨域)
		 * 		7、储存 MappingRegistration 对象
		 */
		public void register(T mapping, Object handler, Method method) {
			this.readWriteLock.writeLock().lock();	//获取写锁
			try {
				HandlerMethod handlerMethod = createHandlerMethod(handler, method);
				assertUniqueMethodMapping(handlerMethod, mapping);
				this.mappingLookup.put(mapping, handlerMethod);//注册RequestMappingInfo 和 HandlerMethod

				List<String> directUrls = getDirectUrls(mapping);
				for (String url : directUrls) {
					this.urlLookup.add(url, mapping);	//注册请求路径与对应的RequestMappingInfo
				}

				String name = null;
				if (getNamingStrategy() != null) {
					name = getNamingStrategy().getName(handlerMethod, mapping);
					addMappingName(name, handlerMethod);//注册请求路径与HandlerMethod
				}

				CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
				if (corsConfig != null) {
					this.corsLookup.put(handlerMethod, corsConfig);//注册HandlerMethod与跨域信息
				}
				//创建及注册 MappingRegistation 信息
				this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
			}
			finally {
				//最后, 释放写锁
				this.readWriteLock.writeLock().unlock();
			}
		}

	}

spring源码地址(已翻译): https://github.com/PazzFj/spring-framework



类介绍:

HandlerMethod : 对应被@Controller 注解的类中的方法, 封装成 HandlerMethod 对象

RequestMappingInfo:对应@RequestMapping 注解中信息,保存为RequestMappingInfo 对象



版权声明:本文为baidu_36327010原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。