1.1 前言

  • 上一章节介绍了请求映射处理组件HandlerMapping的主体处理流程,根据request url 获取对应的处理器Handler,这一章节来详细介绍我们平常最多使用的RequestMappingHandlerMapping的加载,这个HandlerMapping 是怎样加载基于@Controller,@RequestMapping 实现的Controller

2.1 解析

  • 接下来我们关注RequestMappingHandlerMapping这个HandlerMapping,因为这个是我们开发过程中最为常用的HandlerMapping,那么它是怎样实现HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; 这个方法,先看一下RequestMappingHandlerMapping的继承关系
image
image

2.1.1 RequestMappingHandlerMapping 加载过程

  • 由上图可以看到RequestMappingHandlerMapping 的父类AbstractHandlerMethodMapping 实现了InitializingBean 接口,InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类, 在初始化bean的时候都会执行该方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public interface InitializingBean {

/**
* Invoked by a BeanFactory after it has set all bean properties supplied
* (and satisfied BeanFactoryAware and ApplicationContextAware).
* <p>This method allows the bean instance to perform initialization only
* possible when all bean properties have been set and to throw an
* exception in the event of misconfiguration.
* @throws Exception in the event of misconfiguration (such
* as failure to set an essential property) or if initialization fails.
*/
void afterPropertiesSet() throws Exception;

}
  • 下面是Spring Bean的生命周期图
  • 查看AbstractHandlerMethodMappingafterPropertiesSet()的实现
1
2
3
4
5
6
7
/**
* Detects handler methods at initialization.
*/
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
  • 又抽象了一个方法,通过方法名可以得到它的用途是初始化HandlerMethods,进入initHandlerMethods(); 方法,这个方法是扫描ApplicationContext 所有的bean,如果发现了该bean所在的类有@Controller注解及@RequestMapping注解的话,则检查这个类的所有方法,如果是标注了@RequestMapping注解的方法则会注册为HandlerMethod
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
/**
* Scan beans in the ApplicationContext, detect and register handler methods.
* @see #isHandler(Class)
* @see #getMappingForMethod(Method, Class)
* @see #handlerMethodsInitialized(Map)
*/
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
// 首先拿到容器的所有的beanName数组
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));

for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
// 得到bean类型
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);
}
}
// 检查bean所在的类是否有Controller注解及RequestMapping注解
if (beanType != null && isHandler(beanType)) {
// 负责将Handler保存到Map里
detectHandlerMethods(beanName);
}
}
}
// 对Handler进行一些初始化,是一个模板方法
handlerMethodsInitialized(getHandlerMethods());
}

String[] beanNames 示例

iamge
iamge
  • 进入isHandler(beanType)方法,,此方法由RequestMappingHandlerMapping实现, 此方法检查bean所在的类是否有@Controller注解及@RequestMapping注解,可以看到此方法的实现是在RequestMappingHandlerMapping里,是不是看到了我们熟悉的两个注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /**
    * 检查bean所在的类是否有Controller注解及RequestMapping注解
    * {@inheritDoc}
    * Expects a handler to have a type-level @{@link Controller} annotation.
    */
    @Override
    protected boolean isHandler(Class<?> beanType) {
    return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
    AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }
  • 如果该beanController注解及RequestMapping注解,则执行detectHandlerMethods(beanName);方法,下面举个例子,我们有一个UserController里面有五个方法,下面来看是怎么处理这个类的

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
@RestController
@RequestMapping("/pub/account")
public class UserController {

@Autowired
private UserService userService;

@GetMapping("/list")
public List<User> findAll() {
return userService.findAll();
}

@GetMapping("/view")
public User view() {
return userService.findById(1);
}

@GetMapping("/{id}")
public User view(@PathVariable("id") Integer id) {
return userService.findById(id);
}

@PostMapping("/")
public void updateUser(@RequestBody User user) {
User user1 = userService.findById(user.getId());
user1.setUsername("update");
userService.saveSelective(user1);
}

@DeleteMapping("/{id}")
public void deleteUser(@PathVariable("id") Integer id) {
userService.logicDeleteOne(id);
}
}
  • 进入detectHandlerMethods(beanName);方法,可以看到Map<Method, T> methods = MethodIntrospector.selectMethods 获取到了我们五个方法,Map<Method, T> methodsMethod为key,RequestMappingInfo为value
image
image
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
/**
* 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) {
// 获取Handler的类型
Class<?> handlerType = (handler instanceof String ?
getApplicationContext().getType((String) handler) : handler.getClass());
final Class<?> userType = ClassUtils.getUserClass(handlerType);

// 这里获取 RequestMapping方法,会过滤掉普通方法
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
@Override
public T inspect(Method method) {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
}
});

if (logger.isDebugEnabled()) {
logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
}
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
// 注册 mappingRegistry
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
  • 进入getMappingForMethod(method, userType) ,此方法在RequestMappingHandlerMapping实现,这里解析分两步解析,一个是方法method解析,另一个是方法所在类handlerType的解析,然后拼接成一个RequestMappingInfo,可以看到也是对RequestMapping注解的解析
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
41
42
43
44
45
46
47
48
49
/**
* 没有使用 {@code @RequestMapping} 注解会返回null
* 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) {
// 解析method的@RequestMapping
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
// 解析Class的@RequestMapping
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
// 合并两个RequestMappingInfo 比如url拼接
info = typeInfo.combine(info);
}
}
// 不是RequestMapping方法返回null
return info;
}


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);
}

protected RequestMappingInfo createRequestMappingInfo(
RequestMapping requestMapping, RequestCondition<?> customCondition) {
// 用@RequestMapping的属性生成RequestMappingInfo
return RequestMappingInfo
.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
.methods(requestMapping.method())
.params(requestMapping.params())
.headers(requestMapping.headers())
.consumes(requestMapping.consumes())
.produces(requestMapping.produces())
.mappingName(requestMapping.name())
.customCondition(customCondition)
.options(this.config)
.build();
}
  • RequestMappingInfo.java 对请求映射的一个抽象,它包含了请求路径,请求方法,请求头等信息。其实可以看做是@RequestMapping的一个对应类。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {

private final String name;

private final PatternsRequestCondition patternsCondition;

private final RequestMethodsRequestCondition methodsCondition;

private final ParamsRequestCondition paramsCondition;

private final HeadersRequestCondition headersCondition;

private final ConsumesRequestCondition consumesCondition;

private final ProducesRequestCondition producesCondition;

private final RequestConditionHolder customConditionHolder;

...
  • 返回到detectHandlerMethods方法
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
protected void detectHandlerMethods(final Object handler) {
// 获取Handler的类型
Class<?> handlerType = (handler instanceof String ?
getApplicationContext().getType((String) handler) : handler.getClass());
final Class<?> userType = ClassUtils.getUserClass(handlerType);

// 这里获取 RequestMapping方法,会过滤掉普通方法
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
@Override
public T inspect(Method method) {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
}
});
if (logger.isDebugEnabled()) {
logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
}
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
// 注册 mappingRegistry
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
  • 得到Map<Method, T> methods之后,就是把这些信息保存起来,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
31
32
33
34
35
36
37
38
39
40
41
42
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}

public void register(T mapping, Object handler, Method method) {
// 加锁
this.readWriteLock.writeLock().lock();
try {
// 创建HandlerMethod
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);

if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
}
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) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}

CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
/**
* private final Map<T, MappingRegistration<T>> registry = new HashMap<T, MappingRegistration<T>>();
* key: RequestMappingInfo
*/
this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
  • 查看private final Map<T, MappingRegistration<T>> registry 对象,见下图key值是RequestMappingInfo valueMappingRegistration
image
image

MappingRegistration.java

1
2
3
4
5
6
7
8
9
10
11
private static class MappingRegistration<T> {

private final T mapping;

private final HandlerMethod handlerMethod;

private final List<String> directUrls;

private final String mappingName;

...

3.1 总结

  • Spring Mvc提供了各种各样的抽象,你能感受到面向对象的魅力。

    • RequestMappingInfo 这个类是对请求映射的一个抽象,它包含了请求路径,请求方法,请求头等信息。其实可以看做是@RequestMapping的一个对应类。

    • HandlerMethod这个类封装了处理器实例(Controller Bean)和 处理方法实例(Method)以及方法参数数组(MethodParameter[])

    • MethodParameter 这个类从2.0就有了,它封装了方法某个参数的相关信息及行为,如该参数的索引,该参数所属方法实例或构造器实例,该参数的类型等。

    • HandlerMapping 该接口的实现类用来定义请求和处理器之前的映射关系,其中只定义了一个方法getHandler

    • AbstractHandlerMethodMapping 这是HandlerMapping的一个基本实现类,该类定义了请求与HandlerMethod实例的映射关系。

    • RequestMappingInfoHandlerMapping这个是AbstractHandlerMethodMapping的实现类,他维护了一个RequestMappingInfoHandlerMethod的Map属性。

    • RequestMappingHandlerMapping 这个是RequestMappingInfoHandlerMapping的子类,它将@RequestMapping注解转化为RequestMappingInfo实例,并为父类使用。也就是我们处理@RequestMapping的终点。

    • InitializingBean 这个接口定义了其实现Bean在容器完成属性设置后可以执行自定义初始化操作,我们的AbstractHandlerMethodMapping便实现了这个接口,并且定义了一组自定义操作,就是用来检测处理我们的@RequestMapping注解。

  • RequestMappingHandlerMapping 这个类的初始化过程主要是构建private final MappingRegistry mappingRegistry的过程,用于找出被@RequestMapping注解修饰的方法,并构造成HanderMethod对象,然后就是放到MappingRegistry mappingRegistry对象中,用于根据request找到对应的处理方法并调用

4.1 参考

官方文档: https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html

https://www.cnblogs.com/taotingkai/p/8438360.html