github原文链接 https://github.com/DespairYoke/java-advance。创作不易,请给个免费的star,已表支持。
前面我们分析了spring如何接入Servlet,执行onRefresh方法,而HandlerMapping的初始化就在OnRefresh中调用。
protected void onRefresh(ApplicationContext context) {
System.out.println("=======dispatherServlet onfresh");
initStrategies(context);
}
initStrategies
方法是所有初始化的集合
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
这里我们只关注initHandlerMappings(context)
。
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
}
我们忽略其他直接看重点getDefaultStrategies
,此函数是加载所有的HandlerMapping.class
.
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
String key = strategyInterface.getName();
String value = defaultStrategies.getProperty(key);
for (String className : classNames) {
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
Object strategy = createDefaultStrategy(context, clazz);
}
}
-
defaultStrategies.getProperty(key)
是通过加载DispatcherServlet同级目录下的DispatcherServlet.properties
文件,获取需要执行的实现类。properties文件内容如下
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
由文件内容可知获取后类是BeanNameUrlHandlerMapping
和RequestMappingHandlerMapping
.
-
createDefaultStrategy
对获取后的class进行进行bean实例化。
protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
return context.getAutowireCapableBeanFactory().createBean(clazz);
}
实例化时,我们可以注意到一个细节是InitializingBean
类的中的afterPropertiesSet
方法回调。
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
((InitializingBean) bean).afterPropertiesSet();
}
}
而BeanNameUrlHandlerMapping
和RequestMappingHandlerMapping
中,只有RequestMappingHandlerMapping
满足afterPropertiesSet。也正是我们想要的执行回调。
@Override
public void afterPropertiesSet() {
this.config = new RequestMappingInfo.BuilderConfiguration();
this.config.setUrlPathHelper(getUrlPathHelper());
this.config.setPathMatcher(getPathMatcher());
this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
this.config.setContentNegotiationManager(getContentNegotiationManager());
super.afterPropertiesSet();
}
- useSuffixPatternMatch 默认为true,作用是匹配
url.*
- useTrailingSlashMatch 默认为true, 作用是尾部加上
/
重点在super.afterPropertiesSet();
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
回调的目的是初始化所有的方法HandlerMethods
protected void initHandlerMethods() {
for (String beanName : beanNames) {
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
-
isHandler
方法时对bean类型进行判断
@Override
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
-
detectHandlerMethods
是对满足条件的bean进行处理。
protected void detectHandlerMethods(final Object handler) {
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
return getMappingForMethod(method, userType);
} //处理类中所有的方法
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);//把每个处理过后的method,和处理时的相关信息mapping保存
});
}
}
下面看下spring如何对method进行处理的。
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;
}
原来spring创建了一个RequestMappingInfo
来保存method相关信息。具体什么信息,跟踪到createRequestMappingInfo
中。
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();
}
原来是储存@RequestMapping
注解的信息,如常用的value=hello
- 再回到
detectHandlerMethods
方法,看下registerHandlerMethod
方法
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
发现spring用一个名为mappingRegistry
类,存储mapping,handler和method。
到此initHandlerMapping就完成了所有操作。那我们发挥自己的想象,当请求来时,一定会来mappingRegistry进行匹配相关信息。
后续会有相关介绍,请等待下文。