本文介绍springmvc被springboot整合之后,web容器注册spring容器,初始化DispatcherServlet,controller里面的方法注册,访问过程。
首先从springboot-autoconfigure包下面的META-INF/spring-factories里面找到WebMvcAutoConfiguration这个自动配置类,在209行会看到RequestMappingHandlerMapping这个类被创建成bean,这个类有个afterPropertiesSet()方法,在spring容器初始化就会调用这个方法,这个方法用来处理所有标记有@controller的注解的类,并找出所有标记@RequestMapping注解的方法,存到HandlerMethod类里。等第一次访问时就走DispathServlet的init初始化流程
注册类
部分代码
在spring-factories文件里会找到DispatcherServletAutoConfiguration和WebMvcAutoConfiguration,其他的类那你也可以自己打开看看,断点调试。
spring.factories文件中部分代码
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
进入DispatcherServletAutoConfiguration类打断点可以看到图,这里会注册一个dispatchServlet,拦截路径是 / 。后面访问的时候会进入初始化方法init()。
断点进入AbstractHandlerMethodMapping类
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
/**
* Scan beans in the ApplicationContext, detect and register handler methods.
* @see #getCandidateBeanNames()
* @see #processCandidateBean
* @see #handlerMethodsInitialized
*/
protected void initHandlerMethods() {
// 获取spring容器中所有的bean,进行处理
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
//处理bean的方法,会进行过滤
processCandidateBean(beanName);
}
}
// 空方法
handlerMethodsInitialized(getHandlerMethods());
}
看截图
这里会进入发现处理的方法。看判断的isHandler(beanType)这个方法,这里进行过滤
@Override
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
//找到所有的方法,可以进入这里看看
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));
}
else if (mappingsLogger.isDebugEnabled()) {
mappingsLogger.debug(formatMappings(userType, methods));
}
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
// 注册方法到map中
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
注册方法AbstractHandlerMethodMapping这个类中
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 = createHandlerMethod(handler, method);
//校验是否已经存在
validateMethodMapping(handlerMethod, mapping);
Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
for (String path : directPaths) {
this.pathLookup.add(path, mapping);
}
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
corsConfig.validateAllowCredentials();
this.corsLookup.put(handlerMethod, corsConfig);
}
// 注册到map中,以后拿处理器映射器从这里找
this.registry.put(mapping,
new MappingRegistration<>(mapping, handlerMethod, directPaths, name, corsConfig != null));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
页面访问任意路径:
因为dispatchServlet是一个servlet,所以第一次访问的时候会进行初始化,首先访问的是HttpServletBean类中的init方法,具体类结构看下图。再访问frameWorkServlet中的initServletBean方法。会初始化initWebApplicationContext();和initFrameworkServlet();完成初始化
图1 类结构图
图2 初始化方法
初始化完成之后,进入FrameWorkServlet类中的doPost...方法,再进入processRequest(request, response);这个方法,最后会进入DispatchServlet中的doService()设置一些属性之后,进入doDispatch(request, response);这个方法,进行查找处理器映射器HandlerExecutionChainmappedHandler = getHandler(processedRequest);
再查找处理器适配器HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
再找到视图
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
处理返回结果
最后进入
mappedHandler.triggerAfterCompletion(request, response, null);
执行拦截器的方法,如果没有自定义的,这里跳过,不执行。
就总结这些了。。。。