基本流程
源码分析
Servlet的生命周期方法
Servlet接口如下:
public interface Servlet {
/**
* Serrvlet初始化方法,Servlet对象创建之后调用
*/
public void init(ServletConfig config) throws ServletException;
/**
* Servlet对象被`HTTP`请求访问时调用
*/
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
/**
* 销毁方法
*/
public void destroy();
}
- init:
Servlet对象创建之后调用 - service:
Servlet对象被HTTP请求访问时调用 - destroy:
Servlet对象销毁之前调用
DispatcherServlet继承体系
InitializingBean接口介绍
在我们介绍Spring源码分析的提到该接口,该接口会在bean实例化并且填充完属性之后,准备调用init-method初始化方法之前就会调用实现了InitializingBean接口的afterPropertiesSet方法。这部分可以查看Spring源码。
在下面我们在分析处理器映射器HandlerMapping和处理器适配器HandlerAdapter时,发现两者都实现了InitializingBean接口。
DispatcherServlet主流程
DispatcherServlet初始化流程
入口:GenericServlet#init(config)
接下来准备调用GenericServlet#init()方法了,不过该方法它没有实现,而是被子类HttpServletBean给覆盖了,我们直接看看HttpServletBean#init()方法吧。
/**
* GenericServlet中的init方法真正调用子类HttpServletBean的init方法
*/
@Override
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
// Set bean properties from init parameters.
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
}
}
// Let subclasses do whatever initialization they like.
//真正调用该方法
//接着调用子类FrameworkServlet中的initServletBean方法
initServletBean();
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
接着查看上面代码中的initServletBean()方法,不过该方法需要去HttpServletBean的子类FrameworkServlet中去看看
/**
* 真正调用该方法
*/
@Override
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
if (logger.isInfoEnabled()) {
logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
}
long startTime = System.currentTimeMillis();
try {
//重点 初始化Web环境中的Spring容器WebApplicationContext
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
catch (ServletException | RuntimeException ex) {
logger.error("Context initialization failed", ex);
throw ex;
}
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
elapsedTime + " ms");
}
}
接着查看上面代码中的initWebApplicationContext()方法
/**
* 初始化Web环境中的Spring容器WebApplicationContext
*/
protected WebApplicationContext initWebApplicationContext() {
//父容器
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
//子容器
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
wac = findWebApplicationContext();
}
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
synchronized (this.onRefreshMonitor) {
//刷新容器中的策略
//重点,该方法用于创建Spring容器
onRefresh(wac);
}
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
//将Spring容器存入到ServletContext上下文
getServletContext().setAttribute(attrName, wac);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
"' as ServletContext attribute with name [" + attrName + "]");
}
}
return wac;
}
上述代码主要根据springmvc.xml配置文件创建spring容器,onRefresh()方法是初始化一些默认组件,比如HandlerMapping组件中的(BeanNameURLHandlerMapping),但是该方法最终在DispatcherServlet中调用,我们进入这个方法看看。
/**
* This implementation calls {@link #initStrategies}.
*/
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
/**
* 初始化方法
*/
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);//初始化文件上传解析器
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);//初始化处理器映射器
initHandlerAdapters(context);//初始化处理器适配器
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);//初始化视图解析器
initFlashMapManager(context);
}
看到了这个地方,我想大家已经明白入门程序为什么没有配置三大组件,Spring容器中却依然有这些组件了吧。这个地方初始化了很多默认配置,我们随便找个initHandlerMapping来了解一下它们是怎么实现的吧
/**
*
*/
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
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 {
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.
}
}
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
if (this.handlerMappings == null) {
//重点
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
上述代码中重点在getDefaultStrategies(context, HandlerMapping.class)方法,该方法获取默认的处理器解析器。接下来查看该方法,如下:
从上述截图,我们可以发现,
defaultStrategies中的值就是从DispatcherServlet.properties中读取并且解析得到的,而该文件在如下包中。
该文件的内容如下:
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
# 处理器映射器的所有实现类
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
# 适配器处理器的所有实现类
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
# 视图解析器默认使用的实现类
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
总结
DispatcherServlet初始化流程就是将DispatcherServlet.properties配置文件进行解析,得到默认的配置信息,之后创建出默认的处理器映射器集合,处理器适配器集合和视图解析器等等。至此,DispatcherServlet初始化工作就完成了。
DispatcherServlet核心处理流程
入口类:org.springframework.web.servlet.DispatcherServlet。
该类的继承结构如下:
由继承结构图可知,
DispatcherServlet,直接继承了FrameworkServlet,间接实现了Servlet接口。间接继承了HttpServletBean,,而类HttpServletBean是直接继承HttpServlet的。如下图所示
首先从父类FrameworkServlet的doGet和doPost方法看起,如下图所示
/**
* Delegate GET requests to processRequest/doService.
* <p>Will also be invoked by HttpServlet's default implementation of {@code doHead},
* with a {@code NoBodyResponse} that just captures the content length.
* @see #doService
* @see #doHead
* 先看该方法,接着看该方法中的processRequest方法
*/
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//重点
processRequest(request, response);
}
/**
* Delegate POST requests to {@link #processRequest}.
* @see #doService
*/
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//重点
processRequest(request, response);
}
/**
* Process this request, publishing an event regardless of the outcome.
* <p>The actual event handling is performed by the abstract
* {@link #doService} template method.
*
* 重点,真正调用该方法
*/
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
initContextHolders(request, localeContext, requestAttributes);
try {
//重点,该方法为抽象方法,所以调用子类DispatcherServlet中的doService方法
doService(request, response);
}
catch (ServletException | IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
if (logger.isDebugEnabled()) {
if (failureCause != null) {
this.logger.debug("Could not complete request", failureCause);
}
else {
if (asyncManager.isConcurrentHandlingStarted()) {
logger.debug("Leaving response open for concurrent processing");
}
else {
this.logger.debug("Successfully completed request");
}
}
}
publishRequestHandledEvent(request, response, startTime, failureCause);
}
/**
* Subclasses must implement this method to do the work of request handling,
* receiving a centralized callback for GET, POST, PUT and DELETE.
* <p>The contract is essentially the same as that for the commonly overridden
* {@code doGet} or {@code doPost} methods of HttpServlet.
* <p>This class intercepts calls to ensure that exception handling and
* event publication takes place.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
* @see javax.servlet.http.HttpServlet#doGet
* @see javax.servlet.http.HttpServlet#doPost
*/
protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
throws Exception;
}
不管是doGet还是doPost方法,最终都会调用processRequest方法,而在processRequest方法中核心代码逻辑是doService(request, response),但是该方法在父类FrameworkServlet中是一个抽象方法,真正实现在子类中【这里用到了MyBatis源码涉及的设计模式提到的适配器设计模式】。
接着重点查看子类DispatcherServlet中的doService方法,如下:
/**
* Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
* for the actual dispatching.
* 重点
*/
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
}
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
if (this.flashMapManager != null) {
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}
try {
//重点,处理请求分发
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
重点是doDispatch(request, response)代码,接着查看doDispatch方法,如下:
/**
* Process the actual dispatching to the handler.
* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
* to find the first that supports the handler class.
* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
* themselves to decide which methods are acceptable.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
* 重点,处理请求分发
*/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
//处理器执行链对象
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//处理文件上传的request请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
/**
* 重点,点进去看看源码逻辑
*
* 通过处理器映射器HandlerMapping,获取handler处理器执行链,即HandlerExecutionChain对象
* 该执行链封装了处理器即Handler对象和对应处理器的拦截器即HandlerInterceptor(可能有多个).
* 需要注意的是@Controller注解的类,它不是我们这里要查找的处理器,我们要找的处理器是@RequestMapping对应的方法,
* 这个方法会在
*
*/
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
//重点,点进去看看源码逻辑
//通过找到的Handler处理器,去匹配合适的处理器适配器HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//执行拦截器interceptor的preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
//重点
//通过处理器适配器,真正调用处理器方法
//真正调用AbstractHandlerMethdAdapter类中的handle方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//设置默认视图名称
applyDefaultViewName(processedRequest, mv);
//执行拦截器interceptor的postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//重点,点进去看源码
//处理调度结果(也就是ModelAndView对象)
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
//执行拦截器interceptor的afterCompletion方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
//执行拦截器interceptor的afterCompletion方法
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
doDispatch方法的流程如下:
处理器映射器
注册流程
本章节主要是分析注解方式的处理器映射器:
RequestMappingHandlerMapping:根据@RequestMapping注解查找处理器(HandlerMethod)
由于RequestMappingHandlerMapping间接实现了InitializingBean,所以该对象在实例化并且填充属性之后,在调用初始化方法之前就会调用afterPropertiesSet方法。
分析入口:RequestMappingHandlerMapping#afterPropertiesSet方法
接着查看AbstractHandlerMethodMapping的afterPropertiesSet方法。
我们继续去看看detectHandlerMethods方法(核心处理方法)
/**
* 重点
* 从Controller或者RequestMapping注解的Bean中,找到所有的HnadlerMethod对象,并进行存储
*/
protected void detectHandlerMethods(Object handler) {
//获取处理器类型
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
//如果该类是通过cglib代理的代理类,则获取其父类类型,否则的话,直接返回该类
Class<?> userType = ClassUtils.getUserClass(handlerType);
/**
* 存储Method方法和RequestMapping注解信息的映射关系(重点)
* 该映射关系会解析成我们需要的其他两个映射关系
* key是Controller类中的Method对象,value是RequestMappingInfo对象(即@RequestMapping注解中的属性信息)
*/
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {//此处是设置回调函数
try {
//获取bean上面和method上面的RequestMapping注解信息,则装到RequestMappingInfo对象中
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);
}
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
//注册HandlerMethod和RequestMappingInfo对象的关系
//注册请求URL和RequestMappingInfo对象关系
//重点
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
上面的方法处理逻辑主要分为两大步骤:
- 映射
Method和RequestMappingInfo的关系 - 映射关系:
RequestMappingInfo与URL和HandlerMethod的关系。
我们先看第一大步骤,也就是调用MethodIntrospector的selectMethods方法
接着我们去看一下MetadataLookup的匿名内部类实现中调用的getMappingForMethod方法是如何实现的?需要去RequestMappingHandlerMapping类中去查看该方法。
/**
* 真正调用该方法
* 获取bean上面和method上面的RequestMapping注解信息,则装到RequestMappingInfo对象中
*/
@Override
@Nullable
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
//从获取指定method对应的RequestMapping注解信息
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
//获取指定bean对应的RequestMapping注解信息
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
//将bean上面的RequestMapping信息和method上面的RequestMapping信息进行合并
info = typeInfo.combine(info);
}
}
return info;
}
@Nullable
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
//获取到@RequestMapping注解中配置的信息
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
RequestCondition<?> condition = (element instanceof Class ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
//查看createRequestMappingInfo方法
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
至此第一大步骤我们阅读完了,接下来去看看第二大步骤,我们看看AbstractHandlerMethodMapping#registerHandlerMethod方法。
接下来,我们去看看register方法
至此处理器映射器的初始化流程就完成了。
处理流程
分析入口:DispatcherServlet#getHandler方法
接下来我们需要进入到具体的AbstractHandlerMapping#getHandler方法
接下来我们重点看看AbstractHandlerMethodMapping#getHandlerInternal方法。
接下来我们重点去看看
lookupHandlerMethod方法(核心方法)
我们继续去看看addMatchingMappings方法
接着去RequestMappingInfoHandlerMapping#getMatchingMapping方法
最后去RequestMappingInfo#getMatchingCondition方法
总结
如下图所示
该处理流程主要是通过URL匹配在初始化时对应存储的RequestMappingInfo,接着通过RequestMappingInfo找到对应的Method,最后封装成HandlerMethod,HandlerMethod类结构如下:
/**
*
* 注意:Controller类和其中的一个Method对象,组成了一个HnadlerMathod对象,该对象就是适配器去适配的Hadler处理器
*/
public class HandlerMethod {
/** Logger that is available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
//该属性就是Controller类
private final Object bean;
@Nullable
private final BeanFactory beanFactory;
private final Class<?> beanType;
//该属性就是Controller类中的带有@RequestMapping注解的方法
private final Method method;
private final Method bridgedMethod;
private final MethodParameter[] parameters;
@Nullable
private HttpStatus responseStatus;
@Nullable
private String responseStatusReason;
@Nullable
private HandlerMethod resolvedFromHandlerMethod;
//省略不重要的部分
}
处理器适配器
注册流程
分析源码入口:RequestMappingHandlerAdapter#afterPropertiesSet
//重点该方法
@Override
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
//初始化Controller类通知缓存
initControllerAdviceCache();
//初始化参数解析器
if (this.argumentResolvers == null) {
//点进去看看getDefaultArgumentResolvers
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
//初始化处理器Binder参数解析器
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
//初始化处理器返回值解析器
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
-
以上方法,分别注册了处理器增强类的相关操作(
@ModelAttribute、@InitBinder、@ExceptionHandler)、参数解析器、initBinder参数解析器、返回值处理器 -
这些注册的参数解析器和返回值处理器会在执行
Handler方法时进行调用。
处理流程
分析源码入口:DispatcherServlet#doDispatcher方法
主要分为两个流程:
-
根据
Handler获取到对应的HandlerAdapter。 -
执行
Handler对应的handle方法,也就是@Controller类中的带有@RequestMapping注解的方法,底层是通过反射来实现的,即Method.invoke(obj,args)
先来看第一个流程: HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
/**
*
* 重点
* 通过找到的Handler处理器,去匹配合适的处理器适配器HandlerAdapter
*/
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
//通过适配器的适配功能,去适配处理器,如果适配成功,则直接返回处理器适配器
if (ha.supports(handler)) {
return ha;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
查看HnadlerAdapter接口的其中一个实现类HttpRequestHandlerAdapter中的supports方法如下:
public class HttpRequestHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}
}
由以上可知,该处理器适配器是适配实现了HttpRequestHandler接口的Handler,第一个流程到此结束。
接下来查看第二个流程: mv = ha.handle(processedRequest, response, mappedHandler.getHandler())
接着调用AbstractHandlerMethdAdapter类中的handle方法
进入RequestMappingHandlerAdapter#handleInternal方法
进入invokeHandlerMethod方法
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
//获取数据绑定工厂,作用是为了获取WebDataBinder,WebDataBinder给参数进行类型转换
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
//设置参数解析器
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
//设置返回值解析器
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
if (logger.isDebugEnabled()) {
logger.debug("Found concurrent result value [" + result + "]");
}
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
//重点
//调用HnadlerMethod
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
接下来查看invocableMethod.invokeAndHandle(webRequest, mavContainer);
/**
* 重点
*/
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//重点流程1
//执行参数解析流程,HnadlerMethod处理流程,并返回i结果
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
//重点流程2
//执行返回值解析流程,主要了解@ResponseBody注解修饰的返回值解析
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
接下来查看invokeForRequest方法,如下:
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//获取方法参数值(这一步也是从request中将参数解析出来的过程)
//重点看一下getMethodArgumentValues源码
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"' with arguments " + Arrays.toString(args));
}
//重点
//执行HandlerMethod方法,并获取返回值(也就是执行Controller类中的方法)
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"] returned [" + returnValue + "]");
}
return returnValue;
}
该方法一共有三个重点流程,如下:
- 获取
Controller类中的对应的方法的请求参数值Object[] args - 执行
Controller类中的对应的方法,底层Method.invoke(obj,args) - 将返回值返回。
咱们这里重点查看第二步骤:执行Controller类中的对应的方法,底层Method.invoke(obj,args)
,于是查看Object returnValue = doInvoke(args);
参数绑定流程
分析入口:InvocableHandlerMethod#invokeForRequest方法
进入getMethodArgumentValues方法
private Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//得到HandlerMethod中的参数集合
MethodParameter[] parameters = getMethodParameters();
//该数组中存放的数据,已经是经过类型转换之后的参数了
Object[] args = new Object[parameters.length];
//遍历每一个参数
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
//初始化参数名称发现者(通过反射获取参数类型容易,但是获取参数名称需要特殊处理)
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
//解决默认支持的参数
args[i] = resolveProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
//根据参数匹配参数解析器
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
//重点
//执行参数解析(将request中将请求数据,绑定到方法参数中)
args[i] = this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
}
throw ex;
}
}
if (args[i] == null) {
throw new IllegalStateException("Could not resolve method parameter at index " +
parameter.getParameterIndex() + " in " + parameter.getExecutable().toGenericString() +
": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
}
}
return args;
}
重点看看HandlerMethodArgumentResolverComposite#resolveArgument方法
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
//找出可以解析该参数的参数解析器
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException("Unsupported parameter type [" +
parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
}
//根据具体参数解析器的参数解析工作
//重点看两个
//1.AbstractNamedValueMethodArgumentResolver:用于解析简单类型参数
//2.ModelAttributeMethodProcessor:用于解析pojo参数类型
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
此处需要根据具体参数类型调用相应的解析器,
-
其中简单类型调用的都是
AbstractNamedValueMethodArgumentResolver类中的方法; -
POJO类型调用的都是ModelAttributeMethodProcessor类中的方法。我们就以简单类型(对应AbstractNamedValueMethodArgumentResolver)为例给大家讲解一下具体的参数绑定过程
//用于解析简单类型的参数
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
//NamedValueInfo对象封装了方法参数(方法名称,是否必须,默认值)三个信息,相当于@RequestParam注解中的三个属性
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
MethodParameter nestedParameter = parameter.nestedIfOptional();
//将方法参数名称处理一下
Object resolvedName = resolveStringValue(namedValueInfo.name);
if (resolvedName == null) {
throw new IllegalArgumentException(
"Specified name must not resolve to null: [" + namedValueInfo.name + "]");
}
//从request请求中解析出来指定的key(参数名称)的值,即request.getParameter("xxx");
//此时从request中解析出来的参数值都是String类型的
Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
//空值处理
if (arg == null) {
//使用默认值设置参数值
if (namedValueInfo.defaultValue != null) {
arg = resolveStringValue(namedValueInfo.defaultValue);
}
else if (namedValueInfo.required && !nestedParameter.isOptional()) {
handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
}
//处理空值情况
arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
}
else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
arg = resolveStringValue(namedValueInfo.defaultValue);
}
//重点
//使用WebDataBinder进行数据类型转换
//WebDataBinder会根据不同的参数,选择不同的PropertyEditor进行参数类型转换
//而大多数的PropertyEditor都已经内置了,那么如果需要自定义添加PropertyEditor的话,需要使用@InitBinder注解的方法进行处理
if (binderFactory != null) {
//获取web数据绑定器,主要作用将request请求参数中的值,转换成指定类型的Controller方法中的参数类型
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
try {
//重点
//使用web绑定器,将string类型的请求数据,转换成指定数据类型,并绑定到指定方法参数中
//此处有两个arg变量,作为参数是string类型,作为返回值,已经变为了其他类型
//parameter是Controller类中的方法的参数,即形参
arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
}
catch (ConversionNotSupportedException ex) {
throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
namedValueInfo.name, parameter, ex.getCause());
}
catch (TypeMismatchException ex) {
throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
namedValueInfo.name, parameter, ex.getCause());
}
}
handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
return arg;
}
我们进入RequestParamMethodArgumentResolver#resolveName方法看看
至于参数绑定器的源码比较复杂,我们就不深入追踪了,我们只需要知道参数转换方式有两种处理方式:
PropertyEditor和ConversionService,以及它们处理参数转换的区别就行了。下面的代码是在**TypeConverterDelegate**类中的
@Override
@Nullable
public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,
@Nullable MethodParameter methodParam) throws TypeMismatchException {
//获取不同的类型转换器,对参数进行绑定
//我们选择TypeConverterSupport转换器
return getTypeConverter().convertIfNecessary(value, requiredType, methodParam);
}
接着查看TypeConverterSupport类中的convertIfNecessary方法
最终来到TypeConverterDelegate类中的convertIfNecessary方法,如下:
/**
* 重点
* 类型转换就看到该方法就行了,到头了,不要再往下挖了
*/
@SuppressWarnings("unchecked")
@Nullable
public <T> T convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue, @Nullable Object newValue,
@Nullable Class<T> requiredType, @Nullable TypeDescriptor typeDescriptor) throws IllegalArgumentException {
// Custom editor for this type?
//获取自定义属性编辑器
//属性编辑器的作用就是string类型转换成任意类型
PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
ConversionFailedException conversionAttemptEx = null;
// No custom editor but custom ConversionService specified?
//获取自定义类型转换服务
//Converter的作用是任意类型到任意类型的转换
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {
TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
try {
//使用自定义的ConversionService,完成类型转换
return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
}
catch (ConversionFailedException ex) {
// fallback to default conversion logic below
conversionAttemptEx = ex;
}
}
}
Object convertedValue = newValue;
//省略不重要代码
}
返回值处理流程
分析入口:ServletInvocableHandlerMethod#invokeAndHandle方法
返回值由this.returnValueHandlers进行处理,这个成员变量的类型是HandlerMethodReturnValueHandlerComposite,它继承自HandlerMethodReturnValueHandler类,该类有两个方法:
我们进入HandlerMethodReturnValueHandlerComposite#handleReturnValue方法
至此返回值处理流程我们就分析完了
ResponseBody注解解析
如果返回值使用@ResponseBody注解,那么由它注解的返回值会使用 RequestResponseBodyMethodProcessor类进行返回值处理。
//处理@ResponseBody注解的返回值处理器
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// Try even with null return value. ResponseBodyAdvice could get involved.
//重点
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
进入AbstractMessageConverterMethodProcessor#writeWithMessageConverters方法,这个方法的处理逻辑比较长,我们挑重点的代码进行阅读
继续深入AbstractGenericHttpMessageConverter#write方法
进入writeInternal方法