controller用于接收请求的注解在spring容器里面的解析过程

spring中对于controller的注解解析和映射的匹配原理

本文中主要针对AbstractMethodHandlerMapping中的每一个方法进行断点并分析原理来了解这一处理过程的。

	/**
	 * Configure the naming strategy to use for assigning a default name to every
	 * mapped handler method.
	 * 

The default naming strategy is based on the capital letters of the * class name followed by "#" and then the method name, e.g. "TC#getFoo" * for a class named TestController with method getFoo. */ 配置命名规则用于对每一个处理器的方法分配一个默认的命名。 这个默认的命名规则是基于类中的大写后面跟着#方法名称 public void setHandlerMethodMappingNamingStrategy(HandlerMethodMappingNamingStrategy<T> namingStrategy) { this.namingStrategy = namingStrategy; }

接着通过下个方法进行

/**
	 * Scan beans in the ApplicationContext, detect and register handler methods.
	 * @see #isHandler(Class)
	 * @see #getMappingForMethod(Method, Class)
	 * @see #handlerMethodsInitialized(Map)
	 */
	 扫描工厂中的所有bean 检测并注册处理器方法
	protected void initHandlerMethods() {
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for request mappings in application context: " + getApplicationContext());
		}
		String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? //detectHandlerMethodsInAncestorContexts
		 																	//默认false
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
				getApplicationContext().getBeanNamesForType(Object.class));获得工厂中的所有class名称

		for (String beanName : beanNames) {
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {  class前缀判断是不是不需要处理的类型
				Class<?> beanType = null;
				try {
					beanType = getApplicationContext().getType(beanName); 获得对应名称下的类型
				}
				catch (Throwable ex) {
					// An unresolvable bean type, probably from a lazy bean - let's ignore it.
					if (logger.isDebugEnabled()) {
						logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
					}
				}
				if (beanType != null && isHandler(beanType)) { 调用子类RequestMappingHandlerMapping的方法主要用于判断是
																不是controller类型详情见下图
					detectHandlerMethods(beanName);
				}
			}
		}
		handlerMethodsInitialized(getHandlerMethods());
	}
-----------------------------------------------------------------------------------------------------------------------
detectHandlerMethods()
/**
	 * 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);
		
		传入两个参数一个 userType ,一个匿名内部类这个类重写了inspect()函数 获得该处理器下的所有方法key为方法value为
		requestMapping的注解(selectMethods方法见 MethodIntrospector.selectMethod()分析)
		Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				new MethodIntrospector.MetadataLookup<T>() {
					@Override
					public T inspect(Method method) {
						return getMappingForMethod(method, userType);
					}
				});

		if (logger.isDebugEnabled()) {
			logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
		}
		将传入的处理器下方法的key值与@requestMapping注解的值 以Map的形式保存
		for (Map.Entry<Method, T> entry : methods.entrySet()) {
			Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
			T mapping = entry.getValue();
			详情见registerHandlerMethod()解析
			registerHandlerMethod(handler, invocableMethod,  );
		}
	}

-----------------------------------------------------------------------------------------------------------------------
registerHandlerMethod()解析
	protected void registerHandlerMethod(Object handler, Method method, T mapping) {
	调用mappingRegistry的注册方法详情见下
		this.mappingRegistry.register(mapping, handler, method);
	}

/**
	 * A registry that maintains all mappings to handler methods, exposing methods
	 * to perform lookups and providing concurrent access.
	 *
	 * 

Package-private for testing purposes. */ 一个注册对象 主要包含处理器的方法的匹配信息 提供方法的查找和并发访问-读写锁 class MappingRegistry { private final Map<T, MappingRegistration<T>> registry = new HashMap<T, MappingRegistration<T>>(); private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<T, HandlerMethod>(); private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<String, T>(); private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<String, List<HandlerMethod>>(); private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<HandlerMethod, CorsConfiguration>(); private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); /** * Return all mappings and handler methods. Not thread-safe. * @see #acquireReadLock() */ public Map<T, HandlerMethod> getMappings() { return this.mappingLookup; } /** * Return matches for the given URL path. Not thread-safe. * @see #acquireReadLock() */ public List<T> getMappingsByUrl(String urlPath) { return this.urlLookup.get(urlPath); } /** * Return handler methods by mapping name. Thread-safe for concurrent use. */ public List<HandlerMethod> getHandlerMethodsByMappingName(String mappingName) { return this.nameLookup.get(mappingName); } /** * Return CORS configuration. Thread-safe for concurrent use. */ public CorsConfiguration getCorsConfiguration(HandlerMethod handlerMethod) { HandlerMethod original = handlerMethod.getResolvedFromHandlerMethod(); return this.corsLookup.get(original != null ? original : handlerMethod); } /** * Acquire the read lock when using getMappings and getMappingsByUrl. */ public void acquireReadLock() { this.readWriteLock.readLock().lock(); } /** * Release the read lock after using getMappings and getMappingsByUrl. */ public void releaseReadLock() { this.readWriteLock.readLock().unlock(); } 注册方法 public void register(T mapping, Object handler, Method method) { this.readWriteLock.writeLock().lock(); try { HandlerMethod handlerMethod = createHandlerMethod(handler, method); assertUniqueMethodMapping(handlerMethod, mapping);判断Map集合中@RquestMapping的注解是否重复 重复则抛出异常 if (logger.isInfoEnabled()) { logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod); } 未重复将注解与方法进行插入mappingLookup this.mappingLookup.put(mapping, handlerMethod); List<String> directUrls = getDirectUrls(mapping); for (String url : directUrls) { 将url与注解插入urlLookup this.urlLookup.add(url, mapping); } String name = null; if (getNamingStrategy() != null) { name = getNamingStrategy().getName(handlerMethod, mapping); 将默认的命名与方法插入nameLookup addMappingName(name, handlerMethod); } CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping); if (corsConfig != null) { this.corsLookup.put(handlerMethod, corsConfig); } this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name)); } finally { this.readWriteLock.writeLock().unlock(); } } private void assertUniqueMethodMapping(HandlerMethod newHandlerMethod, T mapping) { HandlerMethod handlerMethod = this.mappingLookup.get(mapping); 判断是否已经存在相同的注解 if (handlerMethod != null && !handlerMethod.equals(newHandlerMethod)) { throw new IllegalStateException( "Ambiguous mapping. Cannot map '" + newHandlerMethod.getBean() + "' method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '" + handlerMethod.getBean() + "' bean method\n" + handlerMethod + " mapped."); } } private List<String> getDirectUrls(T mapping) { List<String> urls = new ArrayList<String>(1); for (String path : getMappingPathPatterns(mapping)) { if (!getPathMatcher().isPattern(path)) { urls.add(path); } } return urls; } private void addMappingName(String name, HandlerMethod handlerMethod) { List<HandlerMethod> oldList = this.nameLookup.get(name); if (oldList == null) { oldList = Collections.<HandlerMethod>emptyList(); } for (HandlerMethod current : oldList) { if (handlerMethod.equals(current)) { return; } } if (logger.isTraceEnabled()) { logger.trace("Mapping name '" + name + "'"); } List<HandlerMethod> newList = new ArrayList<HandlerMethod>(oldList.size() + 1); newList.addAll(oldList); newList.add(handlerMethod); this.nameLookup.put(name, newList); if (newList.size() > 1) { if (logger.isTraceEnabled()) { logger.trace("Mapping name clash for handlerMethods " + newList + ". Consider assigning explicit names."); } } } public void unregister(T mapping) { this.readWriteLock.writeLock().lock(); try { MappingRegistration<T> definition = this.registry.remove(mapping); if (definition == null) { return; } this.mappingLookup.remove(definition.getMapping()); for (String url : definition.getDirectUrls()) { List<T> list = this.urlLookup.get(url); if (list != null) { list.remove(definition.getMapping()); if (list.isEmpty()) { this.urlLookup.remove(url); } } } removeMappingName(definition); this.corsLookup.remove(definition.getHandlerMethod()); } finally { this.readWriteLock.writeLock().unlock(); } } private void removeMappingName(MappingRegistration<T> definition) { String name = definition.getMappingName(); if (name == null) { return; } HandlerMethod handlerMethod = definition.getHandlerMethod(); List<HandlerMethod> oldList = this.nameLookup.get(name); if (oldList == null) { return; } if (oldList.size() <= 1) { this.nameLookup.remove(name); return; } List<HandlerMethod> newList = new ArrayList<HandlerMethod>(oldList.size() - 1); for (HandlerMethod current : oldList) { if (!current.equals(handlerMethod)) { newList.add(current); } } this.nameLookup.put(name, newList); } }

MethodIntrospector.selectMethod()分析

/**
	 * Select methods on the given target type based on the lookup of associated metadata.
	 * 

Callers define methods of interest through the {@link MetadataLookup} parameter, * allowing to collect the associated metadata into the result map. * @param targetType the target type to search methods on * @param metadataLookup a {@link MetadataLookup} callback to inspect methods of interest, * returning non-null metadata to be associated with a given method if there is a match, * or {@code null} for no match * @return the selected methods associated with their metadata (in the order of retrieval), * or an empty map in case of no match */ public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) { final Map<Method, T> methodMap = new LinkedHashMap<Method, T>(); Set<Class<?>> handlerTypes = new LinkedHashSet<Class<?>>(); Class<?> specificHandlerType = null; 添加处理器类型 if (!Proxy.isProxyClass(targetType)) { handlerTypes.add(targetType); specificHandlerType = targetType; } 添加处理器接口类型 handlerTypes.addAll(Arrays.asList(targetType.getInterfaces())); for (Class<?> currentHandlerType : handlerTypes) { final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType); 调用ReflectionUtils.doWithMethods()的方法并重写doWith()方法 详情见ReflectionUtils.doWithMethods()解析 ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() { @Override public void doWith(Method method) { 获得当前的方法对象 Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass); 调用上个代码块中的detectHandlerMethods()中的 inspect()方法 为了方便查看我这边直接复制过来 ----------------------------------------------------------------------------------------------------------- @Override public T inspect(Method method) { return getMappingForMethod(method, userType); } 这是一个回调函数可以用与查找给定类的指定方法的注解 ----------------------------------------------------------------------------------------------------------- T result = metadataLookup.inspect(specificMethod); if (result != null) { Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod); if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) { 插入注解与方法 methodMap.put(specificMethod, result); } } } }, ReflectionUtils.USER_DECLARED_METHODS); } return methodMap; }

ReflectionUtils.doWithMethods()

/**
	 * Perform the given callback operation on all matching methods of the given
	 * class and superclasses (or given interface and super-interfaces).
	 * 

The same named method occurring on subclass and superclass will appear * twice, unless excluded by the specified {@link MethodFilter}. * @param clazz the class to introspect * @param mc the callback to invoke for each method * @param mf the filter that determines the methods to apply the callback to */ public static void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter mf) { // Keep backing up the inheritance hierarchy. Method[] methods = getDeclaredMethods(clazz);获取该类下的所有方法 for (Method method : methods) { 判断是否是isbirge()桥接器 这个不太懂有懂的请留言指点下 if (mf != null && !mf.matches(method)) { continue; } try { 调用匿名内部类的dowith方法--在上个代码块中 mc.doWith(method); } catch (IllegalAccessException ex) { throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex); } } if (clazz.getSuperclass() != null) { doWithMethods(clazz.getSuperclass(), mc, mf); } else if (clazz.isInterface()) { for (Class<?> superIfc : clazz.getInterfaces()) { doWithMethods(superIfc, mc, mf); } } }

RequestMappingHandlerMapping-isHandler分析

/**
	 * {@inheritDoc}
	 * Expects a handler to have a type-level @{@link Controller} annotation.
	 */
	@Override
	protected boolean isHandler(Class<?> beanType) {
		return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || 扫描是否含有controller注解
				AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); 扫描是否含有RequestMapping注解
	}

	/**
	 * Uses method and type-level @{@link RequestMapping} annotations to create
	 * the RequestMappingInfo.
	 * @return the created RequestMappingInfo, or {@code null} if the method
	 * does not have a {@code @RequestMapping} annotation.
	 * @see #getCustomMethodCondition(Method)
	 * @see #getCustomTypeCondition(Class)
	 */
	@Override
	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;
	}

	/**
	 * Delegates to {@link #createRequestMappingInfo(RequestMapping, RequestCondition)},
	 * supplying the appropriate custom {@link RequestCondition} depending on whether
	 * the supplied {@code annotatedElement} is a class or method.
	 * @see #getCustomTypeCondition(Class)
	 * @see #getCustomMethodCondition(Method)
	 */
	private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
		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);
	}

你可能感兴趣的:(spring源码)