HandlerMapping

# RequestMapping加载策略

DispatcherServlet#initHandlerMappings

private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;
    // detectAllHandlerMappings默认true
    if (this.detectAllHandlerMappings) {
        // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
        Map<String, HandlerMapping> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            // We keep HandlerMappings in sorted order.
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    }
    else {
        //也可以将detectAllHandlerMappings设置为false,并自己指定`name=handlerMapping`的`HandleMapping`
        try {
            HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
            this.handlerMappings = Collections.singletonList(hm);
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Ignore, we'll add a default HandlerMapping later.
        }
    }

    // 如果没有配置HandlerMapping,从resources/org/springframework/web/servlet/DispatcherServlet.properties中读取默认配置
    if (this.handlerMappings == null) {
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
        if (logger.isTraceEnabled()) {
            logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
                    "': using default strategies from DispatcherServlet.properties");
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

DispatcherServlet#getDefaultStrategies

private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";

private static final Properties defaultStrategies;

static {
	// Load default strategy implementations from properties file.
	// This is currently strictly internal and not meant to be customized
	// by application developers.
	try {
		ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
		defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
	}
	catch (IOException ex) {
		throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
	}
}
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
	String key = strategyInterface.getName();
	String value = defaultStrategies.getProperty(key);
	if (value != null) {
		String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
		List<T> strategies = new ArrayList<>(classNames.length);
		for (String className : classNames) {
			try {
				Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
				Object strategy = createDefaultStrategy(context, clazz);
				strategies.add((T) strategy);
			}
			//catch error ...
		}
		return strategies;
	}
	else {
		return new LinkedList<>();
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

默认策略对应的类写在DispatcherServlet.properties

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
    org.springframework.web.servlet.function.support.RouterFunctionMapping
1
2
3

实践中一般使用的是@Controller@RequestMapping来指定请求处理方法,所以以RequestMappingHandlerMapping来分析

该类实现了一些Aware接口和InitializingBean接口,在Bean实例化过程中会被调用。

# 注册拦截器

ApplicationObjectSupport#setApplicationContext

public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
	if (context == null && !isContextRequired()) {
		// Reset internal context state.
		this.applicationContext = null;
		this.messageSourceAccessor = null;
	}
	else if (this.applicationContext == null) {
		// Initialize with passed-in context.
		if (!requiredContextClass().isInstance(context)) {
			throw new ApplicationContextException(
					"Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
		}
		this.applicationContext = context;
		this.messageSourceAccessor = new MessageSourceAccessor(context);
		initApplicationContext(context);
	}
	else {
		// Ignore reinitialization if same context passed in.
		if (this.applicationContext != context) {
			throw new ApplicationContextException(
					"Cannot reinitialize with different application context: current one is [" +
					this.applicationContext + "], passed-in one is [" + context + "]");
		}
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

AbstractHandlerMapping#initApplicationContext

protected void initApplicationContext() throws BeansException {
    //留给子类扩展
	extendInterceptors(this.interceptors);
    //初始化拦截器
	detectMappedInterceptors(this.adaptedInterceptors);
	initInterceptors();
}
1
2
3
4
5
6
7

AbstractHanlerMapping#detectMappedInterceptors

protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
	mappedInterceptors.addAll(
			BeanFactoryUtils.beansOfTypeIncludingAncestors(
					obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}
1
2
3
4
5

# 注册请求处理类

RequesMappingtHandlerMapping#afterPropertiesSet

public void afterPropertiesSet() {
	this.config = new RequestMappingInfo.BuilderConfiguration();
	this.config.setUrlPathHelper(getUrlPathHelper());
	this.config.setPathMatcher(getPathMatcher());
	this.config.setSuffixPatternMatch(useSuffixPatternMatch());
	this.config.setTrailingSlashMatch(useTrailingSlashMatch());
	this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
	this.config.setContentNegotiationManager(getContentNegotiationManager());

	super.afterPropertiesSet();
}
1
2
3
4
5
6
7
8
9
10
11

AbstractHandlerMethodMapping#afterPropertiesSet

public void afterPropertiesSet() {
	initHandlerMethods();
}
1
2
3

AbstractHandlerMethodMapping#initHandlerMethods

protected void initHandlerMethods() {
	//获取容器中Bean,实例化
	for (String beanName : getCandidateBeanNames()) {
		if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
			processCandidateBean(beanName);
		}
	}
	handlerMethodsInitialized(getHandlerMethods());
}
1
2
3
4
5
6
7
8
9

AbstractHandlerMethodMapping#getCandidateBeanNames

protected String[] getCandidateBeanNames() {
	//是否获取父容器Bean,默认false
	return (this.detectHandlerMethodsInAncestorContexts ?
			BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
			obtainApplicationContext().getBeanNamesForType(Object.class));
}
1
2
3
4
5
6

AbstractHandlerMethodMapping#processCandidateBean

protected void processCandidateBean(String beanName) {
	Class<?> beanType = null;
	try {
		//实例化
		beanType = obtainApplicationContext().getType(beanName);
	}
	catch (Throwable ex) {
		// An unresolvable bean type, probably from a lazy bean - let's ignore it.
		if (logger.isTraceEnabled()) {
			logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
		}
	}
	//isHandler选取要处理的类型 交由之类实现
	if (beanType != null && isHandler(beanType)) {
		detectHandlerMethods(beanName);
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

子类实现匹配请求处理类的方法 RequestMappingHandlerMapping#isHandler

//处理Controller和RequestMapping注解标注的类
protected boolean isHandler(Class<?> beanType) {
	return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
			AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
1
2
3
4
5

AbstractHandlerMethodMapping#detectHandlerMethods

protected void detectHandlerMethods(Object handler) {
	//如果是bean名称,再获取一遍
	Class<?> handlerType = (handler instanceof String ?
			obtainApplicationContext().getType((String) handler) : handler.getClass());

	if (handlerType != null) {
		Class<?> userType = ClassUtils.getUserClass(handlerType);
		//获取请求处理方法的map key=目标方法,value=请求路径、类型等信息
		Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				(MethodIntrospector.MetadataLookup<T>) method -> {
					try {
						//解析方法上的RequestMapping注解请求路径、类型等信息
						return getMappingForMethod(method, userType);
					}
					catch (Throwable ex) {
						throw new IllegalStateException("Invalid mapping on handler class [" +
								userType.getName() + "]: " + method, ex);
					}
				});
		if (logger.isTraceEnabled()) {
			logger.trace(formatMappings(userType, methods));
		}
		methods.forEach((method, mapping) -> {
			Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
			//注册URL与对应处理方法
			registerHandlerMethod(handler, invocableMethod, mapping);
		});
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

子类实现获取handler中处理请求方法的方法 RequestMappingHandlerMapping#getMappingForMethod

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);
		}
		String prefix = getPathPrefix(handlerType);
		if (prefix != null) {
			info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
		}
	}
	return info;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

RequestMappingHandlerMapping#createRequestMappingInfo

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);
}
1
2
3
4
5
6

RequestMappingHandlerMapping#createRequestMapping

protected RequestMappingInfo createRequestMappingInfo(
		RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {

	RequestMappingInfo.Builder builder = RequestMappingInfo
			.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
			.methods(requestMapping.method())
			.params(requestMapping.params())
			.headers(requestMapping.headers())
			.consumes(requestMapping.consumes())
			.produces(requestMapping.produces())
			.mappingName(requestMapping.name());
	if (customCondition != null) {
		builder.customCondition(customCondition);
	}
	return builder.options(this.config).build();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

可以发现大部分都是框架定义好的模板方法,RequestMappingHandlerMapping就是实现预留给子类实现的方法,通过处理Controller,RequestMapping注解,得到请求处理类,以及可处理请求的相关参数。

AbstractHandlerMethodMapping#registerHandlerMathod

protected void registerHandlerMethod(Object handler, Method method, T mapping) {
	this.mappingRegistry.register(mapping, handler, method);
}
1
2
3

MappingRegistryAbstractHandlerMethodMapping的内部类,内置多个map,存储请求与处理方法的映射关系。 MappingRegistry#register

public void register(T mapping, Object handler, Method method) {
	// Assert that the handler method is not a suspending one.
	if (KotlinDetector.isKotlinType(method.getDeclaringClass())) {
		Class<?>[] parameterTypes = method.getParameterTypes();
		if ((parameterTypes.length > 0) && "kotlin.coroutines.Continuation".equals(parameterTypes[parameterTypes.length - 1].getName())) {
			throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
		}
	}
	this.readWriteLock.writeLock().lock();
	try {
		//封装
		HandlerMethod handlerMethod = createHandlerMethod(handler, method);
		//校验不能重复添加
		validateMethodMapping(handlerMethod, mapping);
		//绑定URL与处理方法的映射   URL->mapping->(handler,method)
		this.mappingLookup.put(mapping, handlerMethod);
		List<String> directUrls = getDirectUrls(mapping);
		for (String url : directUrls) {
			this.urlLookup.add(url, mapping);
		}

		String name = null;
		if (getNamingStrategy() != null) {
			//命名策略生成路径信息可以作为URL的替代
			name = getNamingStrategy().getName(handlerMethod, mapping);
			addMappingName(name, handlerMethod);
		}
		//跨域设置
		CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
		if (corsConfig != null) {
			this.corsLookup.put(handlerMethod, corsConfig);
		}
		//封装
		this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
	}
	finally {
		this.readWriteLock.writeLock().unlock();
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
上次更新: 2023/04/09, 16:34:32
最近更新
01
go-admin-ui项目仿写练手1-登录页
06-29
02
maven依赖问题
06-17
03
JVM相关命令
02-21
更多文章>