docs/Spring全家桶/SpringMVC源码分析/请求执行流程(二)之执行Handler方法.md
springmvc ִĵڶƪ£һƪУǷ DispatcherServlet#doDispatch ִܽзΪ²裺
HandlerExecutionChain, ȡ HandlerExecutionChain аشController еķһ HandlerInterceptorhandlerAdapterö handler(xxx)HandlerInterceptor#preHandlehandlerAdapter handle(xxx)HandlerInterceptor#postHandleHandlerInterceptor#afterCompletionţǼ HandlerExecutionChain ĻȡԼ handlerAdapter ĻȡϻأĽIJ衣
HandlerInterceptor#preHandleprotected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
// 3\. spring, HandlerInterceptor#preHandle
// mappedHandlerǵ1ȡHandlerExecutionChain
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
...
}
mappedHandlerǵ 1 ȡ HandlerExecutionChain HandlerExecutionChain#applyPreHandle
HandlerExecutionChain#applyPreHandle
/**
* ִ HandlerInterceptor#preHandle
*/
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response)
throws Exception {
// ȡе
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
// ִ preHandle
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
// ʧˣִ HandlerInterceptor#afterCompletion
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
/**
* ִ HandlerInterceptor#afterCompletion
* Ϊ˱֤HandlerInterceptor#afterCompletionִУ
* ķῴڶõ
*/
void triggerAfterCompletion(HttpServletRequest request,
HttpServletResponse response, @Nullable Exception ex) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
// ִ HandlerInterceptor#afterCompletion
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
һ HandlerExecutionChain
HandlerInterceptor handler ɶ
handler HandlerMethodϢͦḻģ bean/beanFactory/method⼸ԣǿԶиֲ
AbstractHandlerMethodAdapter#handleٻص DispatcherServlet#doDispatchִ HandlerInterceptor#preHandle еͷϷhandler ִУҲ controller Уurl ӦķִУ
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
// 4\. ͨȡhandlerAdapterhandle
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
...
}
һ·ȥ RequestMappingHandlerAdapter#invokeHandlerMethod
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// װrequesrequest
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// ȡ @InitBinder עķ
// ǰcontroller @ControllerAdvice ע @InitBinder עķ
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// ȡ @ModelAttribute עķ
// ǰcontroller @ControllerAdvice ע @ModelAttribute עķ
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);
// ModelAndView
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();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// ִControllerķص㣩
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// ؽ
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
е㳤ص㷽ֻһУinvocableMethod.invokeAndHandle(webRequest, mavContainer);ǰIJִֶǰȡ @InitBinder עķȡ @ModelAttribute עķ webRequest(װ request response ) mavContainer(ModelAndView װ) ȡֱӽ invocableMethod.invokeAndHandleִеģ
ServletInvocableHandlerMethod#invokeAndHandle
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// ִhandler
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// RequestHandled ֵspringmvcݸֵжҪҪת
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null
|| mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
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 {
// ؽ
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
throw ex;
}
}
﷽ǵ invokeForRequest ִзȻٸݷķֵ mavContainer RequestHandled ֵؽ invokeForRequest
InvocableHandlerMethod#invokeForRequest
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainermavContainer,
Object... providedArgs) throws Exception {
//
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
// ÷
return doInvoke(args);
}
Ǵ˲Ȼʹ÷зáʵϣִУĵľDzˣ controller handler Уǿָ
// ֱӴ
@RequestMapping("xxx")
public Object test(String name) {
...
}
// ڲϱ@RequestParam@RequestHeaderע
@RequestMapping("xxx")
public Object test(@RequestParam("name") String name,
@RequestHeader("uid") String uid) {
...
}
// IJװΪ
@RequestMapping("xxx")
public Object test(User user) {
...
}
// ķʹform(Ҳk1=v1&2=v2&...ķ)
// ʹ RequestBody ʽΣݷϢ
@RequestMapping("xxx")
public Object test(@RequestBody User user) {
...
}
...
ǰ淶ʱspringmvc springmvc һġ
InvocableHandlerMethod#getMethodArgumentValues
InvocableHandlerMethod#getMethodArgumentValues
protected Object[] getMethodArgumentValues(NativeWebRequest request,
@Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// ȡвԼΪ÷ȡhandlerȻװΪ MethodParameter
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
Object[] args = new Object[parameters.length];
// δÿ
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
// жǷвֵ֧ǰĽ
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
//
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request,
this.dataBinderFactory);
}
catch (Exception ex) {
throw ex;
}
}
return args;
}
Ȼȡ handler IJ (ԼΪ÷ȡ handler ȻװΪ MethodParameter)ȻЩʱõҪķresolvers.supportsParameter(...) resolvers.resolveArgument(...)յõķ HandlerMethodArgumentResolverComposite У
HandlerMethodArgumentResolverComposite
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainermavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
// ȡһ
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException(...);
}
// HandlerMethodArgumentResolver#resolveArgument
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
// еĽ
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
// ҵһ
// HandlerMethodArgumentResolver#supportsParameter
if (resolver.supportsParameter(parameter)) {
result = resolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
ҪDZȻ HandlerMethodArgumentResolver#supportsParameter HandlerMethodArgumentResolver#resolveArgument IJHandlerMethodArgumentResolver Ǹӿڣ
public interface HandlerMethodArgumentResolver {
/**
* ǰǷִ֧ǰ
*/
boolean supportsParameter(MethodParameter parameter);
/**
* Ľ
*/
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
IJˡ springmvc Уṩ˶ֲأ˵ĵԣֶ 26
Щİ£springmvc ֲֶ֧շʽڲƱȽϸӣ漰ִηʽIJչۣȤСвĵ
Ϳʼִ handler ˡǻص InvocableHandlerMethod#invokeForRequest
InvocableHandlerMethod#invokeForRequest
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainermavContainer,
Object... providedArgs) throws Exception {
//
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
// ÷
return doInvoke(args);
}
doInvoke
@Nullable
protected Object doInvoke(Object... args) throws Exception {
// ʹ÷ִз
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
// Ƿ
return getBridgedMethod().invoke(getBean(), args);
}
catch (...) {
...
}
}
ܼ÷зִеģͲˡ
ǻص ServletInvocableHandlerMethod#invokeAndHandle
ServletInvocableHandlerMethod#invokeAndHandle
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// ִhandle
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
...
try {
// ؽ
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
throw ex;
}
}
귽ִкžʹؽ
HandlerMethodReturnValueHandlerComposite#handleReturnValue
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
// ݷһʵhandler
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException(...);
}
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
@Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameterreturnType) {
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
// жǷܴǰ
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
ȡ ReturnValueHandler ·ǰȡ ArgumentResolver ·ReturnValueHandler HandlerMethodReturnValueHandler ࣬HandlerMethodReturnValueHandler £
public interface HandlerMethodReturnValueHandler {
/**
* жϵǰReturnValueHandlerܷreturnType
*/
boolean supportsReturnType(MethodParameter returnType);
/**
* Ĵ
*/
void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
ͬǰһӿҲ
boolean supportsReturnType(xxx)жϵǰ ReturnValueHandler ܷ returnTypevoid handleReturnValue(xxx)Ĵͬأspringmvc Ҳṩ˷dzʵز
ڲķأһʾ
ֵʱ
@Controller
@RequestMapping("/xxx")
public class XxxController {
@RequestMapping("/index")
public String index() {
return "index";
}
}
صҳĽһͼӦ HandlerMethodReturnValueHandler Ϊ ViewNameMethodReturnValueHandler
public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
@Nullable
private String[] redirectPatterns;
// ʡ redirectPatterns settergetter
...
@Override
public boolean supportsReturnType(MethodParameter returnType) {
Class<?> paramType = returnType.getParameterType();
// ִ֧ķֵֵͣΪvoidΪַ
return (void.class == paramType || CharSequence.class.isAssignableFrom(paramType));
}
/**
* Ĵ
*/
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue instanceof CharSequence) {
// viewName Ƿֵ
String viewName = returnValue.toString();
mavContainer.setViewName(viewName);
if (isRedirectViewName(viewName)) {
// ǷҪת
mavContainer.setRedirectModelScenario(true);
}
}
else if (returnValue != null) {
throw new UnsupportedOperationException(...);
}
}
/**
* жǷҪת
*/
protected boolean isRedirectViewName(String viewName) {
// this.redirectPatterns ĬΪnullе setter
return (PatternMatchUtils.simpleMatch(this.redirectPatterns, viewName)
// ƥ redirect: ͷҲ˵Ƿ "redirect:index"ͱýҪת
|| viewName.startsWith("redirect:"));
}
}
ȽϼؼڴעͣͲ˵ˡֵһǣ handleReturnValue(xxx) Уspringmvc صַΪ viewName Ҫע£ڴͼʱ viewName õӦ View
ǻص RequestMappingHandlerAdapter#invokeHandlerMethod
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
...
// ִControllerķ
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// ִнõ ModelAndView
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
ִ invocableMethod.invokeAndHandle(webRequest, mavContainer) žǴִнõ ModelAndView ˣ RequestMappingHandlerAdapter#getModelAndView
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
// ModelFactoryǰȡ @ModelAttribute עķ
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
ModelMap model = mavContainer.getModel();
// ͼmavContainer.getViewName()뵽ModelAndViewĹ췽
ModelAndView mav = new ModelAndView(mavContainer.getViewName(),
model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
// ض
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request != null) {
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
}
return mav;
}
ԿModelAndView Ǵǰִн viewName õġ
ˣAbstractHandlerMethodAdapter#handle ִϡ
HandlerInterceptor#postHandleٻص DispatcherServlet#doDispatch
DispatcherServlet#doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
try {
...
try {
...
// 4.ͨȡhandlerAdapterhandle
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 5.ûзͼʹĬϵ
applyDefaultViewName(processedRequest, mv);
// 6\. ִ HandlerInterceptor#postHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (...) {
...
}
// 7\. ؽִ HandlerInterceptor.afterCompletion
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (...) {
...
}
}
ִ handler Ϳʼִ HandlerInterceptor#postHandle ˣ
HandlerExecutionChain#applyPostHandle
void applyPostHandle(HttpServletRequest request, HttpServletResponse response,
@NullableModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
// ִ postHandle(...)
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
ͬǰִƣͲˡҪǿǣHandlerInterceptor#postHandle ִʱִ handler ֮ͼ֮ǰˣǿﴦһЩȾ
ƪľȵˣrequest ִеḷ́ƪٷ
ԭӣhttps://my.oschina.net/funcy/blog/4741104 ߸ˮƽд֮ӭָԭףҵתϵȨҵתע