1 代码启动类会有注解@EnableWebMvc
2 打开该注解。发现里面有代码
3 打开DelegatingWebMvcConfiguration 发现里面并未定义什么东西,都是一些方法。于是找其父类。WebMvcConfigurationSupport
4 WebMvcConfigurationSupport 中定义了一个bean,这里说一句,@enable**类型的启用注解,大多都是增加一个配置bean,在其初始化过程中实现自己的新增的功能。
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = createRequestMappingHandlerMapping();
handlerMapping.setOrder(0);
handlerMapping.setInterceptors(getInterceptors());
handlerMapping.setContentNegotiationManager(mvcContentNegotiationManager());
handlerMapping.setCorsConfigurations(getCorsConfigurations());
PathMatchConfigurer configurer = getPathMatchConfigurer();
if (configurer.isUseSuffixPatternMatch() != null) {
handlerMapping.setUseSuffixPatternMatch(configurer.isUseSuffixPatternMatch().booleanValue());
}
if (configurer.isUseRegisteredSuffixPatternMatch() != null) {
handlerMapping
.setUseRegisteredSuffixPatternMatch(configurer.isUseRegisteredSuffixPatternMatch().booleanValue());
}
if (configurer.isUseTrailingSlashMatch() != null) {
handlerMapping.setUseTrailingSlashMatch(configurer.isUseTrailingSlashMatch().booleanValue());
}
if (configurer.getPathMatcher() != null) {
handlerMapping.setPathMatcher(configurer.getPathMatcher());
}
if (configurer.getUrlPathHelper() != null) {
handlerMapping.setUrlPathHelper(configurer.getUrlPathHelper());
}
return handlerMapping;
}
5 经过4中配置的bean 就生成了这个bean ,那生成以后如何注册到spring容器中呢?
层层往上,找到该类的父类一直跟到爷爷那一辈,发现继承了父类实现了InitializingBean,那么在初始化的时候就会调用afterPropertiesSet方法。看下父类afterPropertiesSet的实现
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
//detectHandlerMethodsInAncestorContexts默认false,所以是得到所有的beanNames
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
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);
}
}
//2. isHandler由子类实现
if (beanType != null && isHandler(beanType)) {
//3. 查找controller中有@RequestMapping注解的方法,并注册到请求
detectHandlerMethods(beanName);
}
}
}
//空方法
handlerMethodsInitialized(getHandlerMethods());
}
6 这个时候就要和spring-beans工程扯上关系了。目前还是不会i是很清楚,当初读源码的时候隐约记得是,实现了这个接口,就可以在bean初始化之后进行一些其他的操作。这里自己定义的afterPropertiesSet()方法。目的就很简单了,过滤所有的bean,拦截住拥有该注解的类或者bean,然后找到带有注解的方法。(方法名称叫就能看出,这个方法是在bean生成后进行处理的得,所以此时是已经有bean的了。)
7 为了实现第六步,拿到所有bean 和拦截,requestmappinghandlermapping还顺便继承了很多类和实现了很多接口,可以查看下边的 继承关系(一定要学会eclipse的快捷键F4 最好是能看UML关系,如果有幸能看到spring的UML就好了,可惜我不知道哪里有,除了别人的blog,如果有人知道,记得告诉我哦。) 。看下边的继承关系,最终实现的就是applicationcontextAware接口,这个接口的作用就是为了获取applicationcontext 的也就是spring暴露的供我们使用的bean容器。
public abstract class ApplicationObjectSupport implements ApplicationContextAware {
8 绕了一大堆,就是为了说明当bean初始化执行后,会执行该bean的afterPropertiesSet()方法。首先是执行的RequestMappingHandlerMapping 的,内部有调用父类AbstractHandlerMethodMapping的该方法。
9然后一步一步执行,将requestmapping的东西注册到一个map中
AbstractHandlerMethodMapping的内部类。
10调用的时候是dispatchservlet 默认也是用的那个RequestMappingHandlerMapping 类,所以就可以拿到里面的信息,进行匹配和调用。
11 源码中注解的过滤处理等没有仔细看。也就是java的反射的一些东西。后期会看。
12 附件中有一个自定义类似于@requestmapping的注解。请搜索 :简化版@requestmapping注解注册源码
13 参考https://www.jianshu.com/p/8d60bf614200文章,感谢作者。