文章目录
- 名词解释
- 大纲
- 代码
- HiddenHttpMethodFilter.java
- HttpServlet.java
- FrameworkServlet.java
- DispatcherServlet.java
- AbstractHandlerMapping.java
- AbstractHandlerMethodMapping.java
- AbstractHandlerMethodAdapter.java
- RequestMappingHandlerAdapter.java
- HandlerMethodArgumentResolverComposite.java
- HandlerMethodArgumentResolver.java
- ServletInvocableHandlerMethod.java
- InvocableHandlerMethod.java
- RequestParamMethodArgumentResolver.java
- ServletRequestMethodArgumentResolver.java
- AbstractNamedValueMethodArgumentResolver.java
- MapMethodProcessor.java
- ModelAndViewContainer.java
- HandlerMethodReturnValueHandlerComposite.java
- ViewNameMethodReturnValueHandler.java
- ModelFactory.java
- HandlerExecutionChain.java
- ContentNegotiatingViewResolver.java
- Abstractview.java
- InternalResourceView.java
- ServletModelAttributeMethodProcessor.java
- MethodParameter.java
- BeanUtils.java
- ModelAttributeMethodProcessor.java
- ServletRequestDataBinder.java
- ExtendedServletRequestDataBinder.java
- WebDataBinder.java
- DataBinder.java
- AbstractPropertyAccessor.java
- AbstractNestablePropertyAccessor.java
名词解释
handler
对Controller的Bean本身和请求Method的包装,封装了目标方法的信息。
handlerMethod
handlerMethod封装了很多属性,在访问请求方法的时候可以方便的访问到方法、方法参数、方法上的注解、所属类等并且对方法参数封装处理,也可以方便的访问到方法参数的注解等信息。
handler instanceof HandlerMethod
大纲
请求映射
- 主要类:WebMvcAutoConfiguration.java
REST映射原理
- 主要类:HiddenHttpMethodFilter.java SpringMVC中处理请求方式的过滤器
- 入口方法:doFilterInternal()
- 应用:_method自定义
请求映射原理:怎么知道哪个请求谁来处理
-
继承结构:
-
主要类:DispatcherServlet.java
-
主要方法:doDispatch(request, response);
-
落脚点:AbstractHandlerMethodMapping.java
-
其他类:
HttpServlet:doget(),dopost()
FrameworkServlet:doget(),dopost() processRequest() → doService(request, response);
DispatcherServlet:doService()
AbstractHandlerMapping.java
AbstractHandlerMethodMapping.java -
总结:5个handlerMappings,处理器映射
1.RequestMappingHandlerMapping:保存了所有@RequestMapping 和handler的映射规则。项目开启时自动扫描所有的包,把映射规则放入到这个里面。
2.RequestMappingHandlerMapping:保存了所有@RequestMapping 和handler的映射规则,所有的请求映射都在HandlerMapping中。
3.请求进来,挨个尝试所有的HandlerMapping看是否有请求信息。如果有就找到这个请求对应的handler,如果没有就是下一个 HandlerMapping。
4.先根据url找到的第一个Handler,由这个Handler处理,如果就多个的话就会抛出异常。返回handlerMethod
参数处理原理
- 主要类:RequestMappingHandlerAdapter.java
- 主要方法:doDispatch(request, response);
- 落脚点:AbstractHandlerMethodMapping.java
- 其他类:
AbstractHandlerMethodAdapter.java
RequestMappingHandlerAdapter.java
HandlerMethodArgumentResolverComposite.java
HandlerMethodArgumentResolver.java
ServletInvocableHandlerMethod.java
InvocableHandlerMethod.java
RequestParamMethodArgumentResolver.java
ServletRequestMethodArgumentResolver.java
AbstractNamedValueMethodArgumentResolver.java
///
ViewNameMethodReturnValueHandler.java
ModelFactory.java
HandlerExecutionChain.java
ContentNegotiatingViewResolver.java
Abstractview.java
InternalResourceView.java
每个参数都有不同的Resolver进行处理
复杂参数原理:Map、Model
主要类:ModelAndViewContainer.java
其他类:
MapMethodProcessor.java
Map、Model(map、model里面的数据会被放在request的请求域 request.setAttribute)
Map<String,Object> map, Model model, HttpServletRequest request 都是可以给request域中放数据,
Map、Model类型的参数,会返回 mavContainer.getModel();—> BindingAwareModelMap 是Model 也是Map
mavContainer.getModel(); 获取到值的
自定义对象参数:POJO
页面提交的请求数据(GET或者POST),都可以和对象属性进行绑定
主要类:ServletModelAttributeMethodProcessor.java
其他类:
MethodParameter.java
BeanUtils.java
ServletModelAttributeMethodProcessor.java
ServletRequestDataBinder.java
ExtendedServletRequestDataBinder.java
WebDataBinder.java
DataBinder.java
AbstractPropertyAccessor.java
AbstractNestablePropertyAccessor.java
未来我们可以给WebDataBinder里面放自己的Converter;
@FunctionalInterfacepublic interface Converter<S, T>// Converter的总接口
private static final class StringToNumber implements Converter<String, T>
1.Automatic registration of Converter, GenericConverter, and Formatter beans.
• 自动注册 Converter,GenericConverter,Formatter
2.Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).
• 自动使用 ConfigurableWebBindingInitializer ,(DataBinder负责将请求数据绑定到JavaBean上)
/**
* 姓名: <input name="userName"/> <br/>
* 年龄: <input name="age"/> <br/>
* 生日: <input name="birth"/> <br/>
* 宠物姓名:<input name="pet.name"/><br/>
* 宠物年龄:<input name="pet.age"/>
*/
@Data
public class Person {
private String userName;
private Integer age;
private Date birth;
private Pet pet;
}
@Data
public class Pet {
private String name;
private String age;
}
自定义 Converter
//1、WebMvcConfigurer定制化SpringMVC的功能
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
// 不移除;后面的内容。矩阵变量功能就可以生效
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new Converter<String, Pet>() {
@Override
public Pet convert(String source) {
// 啊猫,3
if(!StringUtils.isEmpty(source)){
Pet pet = new Pet();
String[] split = source.split(",");
pet.setName(split[0]);
pet.setAge(Integer.parseInt(split[1]));
return pet;
}
return null;
}
});
}
};
}
代码
HiddenHttpMethodFilter.java
/**
* REST映射源码
*/
public class HiddenHttpMethodFilter extends OncePerRequestFilter {
private static final List<String> ALLOWED_METHODS =
Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(),
HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
public static final String DEFAULT_METHOD_PARAM = "_method";
private String methodParam = DEFAULT_METHOD_PARAM;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// 获取到原生的HttpServletRequest
HttpServletRequest requestToUse = request;
// 判断提交过来的请求是不是POST,并且有没有错误
if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
// 得到request中的DEFAULT_METHOD_PARAM = "_method";的值,也就是<input name="_method" type="hidden" value="post">
String paramValue = request.getParameter(this.methodParam);
// 判断是否为空
if (StringUtils.hasLength(paramValue)) {
// method转为大写
String method = paramValue.toUpperCase(Locale.ENGLISH);
// 判断允许的参数包不包含method
// ALLOWED_METHODS兼容PUT、DELETE、PATCH
if (ALLOWED_METHODS.contains(method)) {
// 传过去新的method,重写了getMethod()
// 包装了原生的method
requestToUse = new org.springframework.web.filter.HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);
}
}
}
// filterChain过滤器链放行的是Wrapper包装后的值,以后调用的getMethod()是Wrapper封装过后的
filterChain.doFilter(requestToUse, response);
}
// 继承了原生的HttpMethodRequestWrapper
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
private final String method;
public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
super(request);
this.method = method;
}
// 重写了method,返回的是传进来的值
@Override
public String getMethod() {
return this.method;
}
}
}
HttpServlet.java
public abstract class HttpServlet extends GenericServlet {
private static final String LSTRING_FILE =
"javax.servlet.http.LocalStrings";
private static final ResourceBundle lStrings =
ResourceBundle.getBundle(LSTRING_FILE);
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String msg = lStrings.getString("http.method_get_not_supported");
sendMethodNotAllowed(req, resp, msg);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String msg = lStrings.getString("http.method_post_not_supported");
sendMethodNotAllowed(req, resp, msg);
}
private void sendMethodNotAllowed(HttpServletRequest req, HttpServletResponse resp, String msg) throws IOException {
String protocol = req.getProtocol();
// Note: Tomcat reports "" for HTTP/0.9 although some implementations
// may report HTTP/0.9
if (protocol.length() == 0 || protocol.endsWith("0.9") || protocol.endsWith("1.0")) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
} else {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
}
}
}
FrameworkServlet.java
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
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(org.springframework.web.servlet.FrameworkServlet.class.getName(), new org.springframework.web.servlet.FrameworkServlet.RequestBindingInterceptor());
initContextHolders(request, localeContext, requestAttributes);
try {
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();
}
logResult(request, response, failureCause, asyncManager);
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
throws Exception;
}
DispatcherServlet.java
/**
* 请求映射
*/
// DispatcherServlet是处理所有请求的开始,是一个sevlet,必然要重写doget(),dopost()
public class DispatcherServlet extends FrameworkServlet {
@Nullable
private List<HandlerMapping> handlerMappings;
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
logRequest(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);
}
RequestPath previousRequestPath = null;
if (this.parseRequestPath) {
previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);
ServletRequestPathUtils.parseAndCache(request);
}
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);
}
}
ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
}
}
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 {
// 检查是否是文件上传请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 决定是哪个handler能处理这个请求
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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 处理完成后执行拦截器
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);
}
// 处理最终的结果,处理派发结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
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);
}
}
}
}
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// handlerMappings处理器映射
// this.handlerMappings = {ArrayList@6528} size = 5
// 0 = {RequestMappingHandlerMapping@8126} 保存了RequestMapping和Handler的映射规则
// 1 = {WelcomePageHandlerMapping@8127}
// 2 = {BeanNameUrlHandlerMapping@8128}
// 3 = {RouterFunctionMapping@8129}
// 4 = {SimpleUrlHandlerMapping@8130}
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable org.springframework.web.servlet.HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
// render是要去的哪个页面
// 开始渲染页面
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
// Exception (if any) is already handled..
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
// 渲染页面
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale =
(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
// 拿到视图名
String viewName = mv.getViewName();
if (viewName != null) {
// We need to resolve the view name.
// 解析视图得到视图名称
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
// Delegate to the View object for rendering.
if (logger.isTraceEnabled()) {
logger.trace("Rendering view [" + view + "] ");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
// 渲染视图,要去的一个页面,拿到页面的数据
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "]", ex);
}
throw ex;
}
}
// 解析视图名
@Nullable
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
Locale locale, HttpServletRequest request) throws Exception {
if (this.viewResolvers != null) {
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
}
return null;
}
}
AbstractHandlerMapping.java
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
}
AbstractHandlerMethodMapping.java
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
try {
return super.getHandlerInternal(request);
}
finally {
ProducesRequestCondition.clearMediaTypesAttribute(request);
}
}
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 拿到原生请求的路径value = "/user"
String lookupPath = initLookupPath(request);
this.mappingRegistry.acquireReadLock();
try {
// 这个路径的请求是谁来处理
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
// 先根据url找
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
// 如果同时找到很多,认为第一个是最佳匹配
if (matches.size() > 1) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
bestMatch = matches.get(0);
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
for (Match match : matches) {
if (match.hasCorsConfig()) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
}
}
else {
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.getHandlerMethod().getMethod();
Method m2 = secondBestMatch.getHandlerMethod().getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException(
// 有两个method和url相同的请求,就会报错
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.getHandlerMethod();
}
else {
return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
}
}
private void addMatchingMappings(Collection<T> mappings, List<org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.Match> matches, HttpServletRequest request) {
for (T mapping : mappings) {
T match = getMatchingMapping(mapping, request);
if (match != null) {
matches.add(new org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.Match(match, this.mappingRegistry.getRegistrations().get(mapping)));
}
}
}
}
AbstractHandlerMethodAdapter.java
public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
}
RequestMappingHandlerAdapter.java
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
@Nullable
private HandlerMethodArgumentResolverComposite argumentResolvers;
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
// 执行目标方法
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
// 执行目标方法
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
// 执行目标方法
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
// 0 = {RequestParamMethodArgumentResolver@8228}
// 1 = {RequestParamMapMethodArgumentResolver@8229}
// 2 = {PathVariableMethodArgumentResolver@8230}
// 3 = {PathVariableMapMethodArgumentResolver@8231}
// 4 = {MatrixVariableMethodArgumentResolver@8232}
// 5 = {MatrixVariableMapMethodArgumentResolver@8233}
// 6 = {ServletModelAttributeMethodProcessor@8234}
// 7 = {RequestResponseBodyMethodProcessor@8235}
// 8 = {RequestPartMethodArgumentResolver@8236}
// 9 = {RequestHeaderMethodArgumentResolver@8237}
// 10 = {RequestHeaderMapMethodArgumentResolver@8238}
// 11 = {ServletCookieValueMethodArgumentResolver@8239}
// 12 = {ExpressionValueMethodArgumentResolver@8240}
// 13 = {SessionAttributeMethodArgumentResolver@8241}
// 14 = {RequestAttributeMethodArgumentResolver@8242}
// 15 = {ServletRequestMethodArgumentResolver@8243}
// 16 = {ServletResponseMethodArgumentResolver@8244}
// 17 = {HttpEntityMethodProcessor@8245}
// 18 = {RedirectAttributesMethodArgumentResolver@8246}
// 19 = {ModelMethodProcessor@8247}
// 20 = {MapMethodProcessor@8248}
// 21 = {ErrorsMethodArgumentResolver@8249}
// 22 = {SessionStatusMethodArgumentResolver@8250}
// 23 = {UriComponentsBuilderMethodArgumentResolver@8251}
// 24 = {PrincipalMethodArgumentResolver@8252}
// 25 = {RequestParamMethodArgumentResolver@8253}
// 26 = {ServletModelAttributeMethodProcessor@8254}
// argumentResolvers参数解析器
// 确定将要执行的目标方法的每一个参数值是什么
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
// 0 = {ModelAndViewMethodReturnValueHandler@8228}
// 1 = {ModelMethodProcessor@8229}
// 2 = {ViewMethodReturnValueHandler@8230}
// 3 = {ResponseBodyEmitterReturnValueHandler@8231}
// 4 = {StreamingResponseBodyReturnValueHandler@8232}
// 5 = {HttpEntityMethodProcessor@8233}
// 6 = {HttpHeadersReturnValueHandler@8234}
// 7 = {CallableMethodReturnValueHandler@8235}
// 8 = {DeferredResultMethodReturnValueHandler@8236}
// 9 = {AsyncTaskMethodReturnValueHandler@8237}
// 10 = {ServletModelAttributeMethodProcessor@8238}
// 11 = {RequestResponseBodyMethodProcessor@8239}
// 12 = {ViewNameMethodReturnValueHandler@8240}
// 13 = {MapMethodProcessor@8241}
// 14 = {ServletModelAttributeMethodProcessor@8242}
// returnValueHandlers返回值处理器
// 是什么样的返回值
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();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// 执行并处理
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 获取ModelAndView对象
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
// 此方法都是来处理mavContainer
// 将所有的数据都放在 ModelAndViewContainer;包含要去的页面地址View。还包含Model数据
@Nullable
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
// 更新mavContainer
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
ModelMap model = mavContainer.getModel();
// 将mavContainer里面的model数据封装成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;
}
}
HandlerMethodArgumentResolverComposite.java
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return false;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return null;
}
}
HandlerMethodArgumentResolver.java
/**
* 参数解析器
*/
public interface HandlerMethodArgumentResolver {
// 是否支持该参数
boolean supportsParameter(MethodParameter parameter);
// 如果支持的话就调用这个参数来解析
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
ServletInvocableHandlerMethod.java
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 执行当前请求,断点去到Controller里面的目标方法
// 真正执行了目标方法
// 确定目标方法每一个参数值
// mavContainer中的defaultModel存储了参数的值
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// 设置响应状态
setResponseStatus(webRequest);
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 {
// 处理返回结果,传进去mavContainer中携带了参数的值
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
}
InvocableHandlerMethod.java
public class InvocableHandlerMethod extends HandlerMethod {
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获取方法所有参数的值
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
// 利用反射调用目标方法
return doInvoke(args);
}
// 获取方法所有参数的值
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获得方法所有的参数
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) {
// Leave stack trace for later, exception may actually be resolved and handled...
if (logger.isDebugEnabled()) {
String exMsg = ex.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw ex;
}
}
return args;
}
}
RequestParamMethodArgumentResolver.java
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
implements UriComponentsContributor {
//0 = {RequestParamMethodArgumentResolver@8682}
@Override
public boolean supportsParameter(MethodParameter parameter) {
// 该参数是否标注RequestParam注解
if (parameter.hasParameterAnnotation(RequestParam.class)) {
if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
return (requestParam != null && StringUtils.hasText(requestParam.name()));
}
else {
return true;
}
}
else {
if (parameter.hasParameterAnnotation(RequestPart.class)) {
return false;
}
parameter = parameter.nestedIfOptional();
if (MultipartResolutionDelegate.isMultipartArgument(parameter)) {
return true;
}
else if (this.useDefaultResolution) {
return BeanUtils.isSimpleProperty(parameter.getNestedParameterType());
}
else {
return false;
}
}
}
//1 = {RequestParamMapMethodArgumentResolver@8701}
@Override
public boolean supportsParameter(MethodParameter parameter) {
// 该参数是否标注RequestParam注解
RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
// 该参数是否是Map类型
return (requestParam != null && Map.class.isAssignableFrom(parameter.getParameterType()) &&
!StringUtils.hasText(requestParam.name()));
}
}
ServletRequestMethodArgumentResolver.java
AbstractNamedValueMethodArgumentResolver.java
public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
@Nullable
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
// 得到参数名,例如id
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
MethodParameter nestedParameter = parameter.nestedIfOptional();
// 计算解析参数名称
Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name);
if (resolvedName == null) {
throw new IllegalArgumentException(
"Specified name must not resolve to null: [" + namedValueInfo.name + "]");
}
// 解析参数的值,得到id的值
Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
if (arg == null) {
if (namedValueInfo.defaultValue != null) {
arg = resolveEmbeddedValuesAndExpressions(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 = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
}
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
try {
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());
}
// Check for null value after conversion of incoming argument value
if (arg == null && namedValueInfo.defaultValue == null &&
namedValueInfo.required && !nestedParameter.isOptional()) {
handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
}
}
handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
return arg;
}
}
MapMethodProcessor.java
public class MapMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {
@Override
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
Assert.state(mavContainer != null, "ModelAndViewContainer is required for model exposure");
return mavContainer.getModel();
}
}
ModelAndViewContainer.java
public class ModelAndViewContainer {
// 请求参数的值
private final ModelMap defaultModel = new BindingAwareModelMap();
public ModelMap getModel() {
if (useDefaultModel()) {
return this.defaultModel;
}
else {
if (this.redirectModel == null) {
this.redirectModel = new ModelMap();
}
return this.redirectModel;
}
}
}
HandlerMethodReturnValueHandlerComposite.java
public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {
private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>();
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return getReturnValueHandler(returnType) != null;
}
@Nullable
private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
// 找到返回值处理器
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
}
ViewNameMethodReturnValueHandler.java
public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
// 处理返回值
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue instanceof CharSequence) {
String viewName = returnValue.toString();
// 保存到mavContainer里面,模型和视图容器
mavContainer.setViewName(viewName);
if (isRedirectViewName(viewName)) {
mavContainer.setRedirectModelScenario(true);
}
}
else if (returnValue != null) {
// should not happen
throw new UnsupportedOperationException("Unexpected return type: " +
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
}
}
}
ModelFactory.java
public final class ModelFactory {
public void updateModel(NativeWebRequest request, ModelAndViewContainer container) throws Exception {
ModelMap defaultModel = container.getDefaultModel();
if (container.getSessionStatus().isComplete()){
this.sessionAttributesHandler.cleanupAttributes(request);
}
else {
this.sessionAttributesHandler.storeAttributes(request, defaultModel);
}
if (!container.isRequestHandled() && container.getModel() == defaultModel) {
// 绑定结果
updateBindingResult(request, defaultModel);
}
}
private void updateBindingResult(NativeWebRequest request, ModelMap model) throws Exception {
// 拿到ModelAndView中所有的key
List<String> keyNames = new ArrayList<>(model.keySet());
for (String name : keyNames) {
Object value = model.get(name);
if (value != null && isBindingCandidate(name, value)) {
String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + name;
if (!model.containsAttribute(bindingResultKey)) {
WebDataBinder dataBinder = this.dataBinderFactory.createBinder(request, value, name);
model.put(bindingResultKey, dataBinder.getBindingResult());
}
}
}
}
}
HandlerExecutionChain.java
public class HandlerExecutionChain {
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
// 执行拦截器
for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
ContentNegotiatingViewResolver.java
public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
implements ViewResolver, Ordered, InitializingBean {
@Override
@Nullable
public View resolveViewName(String viewName, Locale locale) throws Exception {
// 拿到所有请求域中的属性
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
List<MediaType> requestedMediaTypes = getMediaTypes(((ServletRequestAttributes) attrs).getRequest());
if (requestedMediaTypes != null) {
List<View> candidateViews = getCandidateViews(viewName, locale, requestedMediaTypes);
// 获取所有的视图
View bestView = getBestView(candidateViews, requestedMediaTypes, attrs);
if (bestView != null) {
return bestView;
}
}
String mediaTypeInfo = logger.isDebugEnabled() && requestedMediaTypes != null ?
" given " + requestedMediaTypes.toString() : "";
if (this.useNotAcceptableStatusCode) {
if (logger.isDebugEnabled()) {
logger.debug("Using 406 NOT_ACCEPTABLE" + mediaTypeInfo);
}
return NOT_ACCEPTABLE_VIEW;
}
else {
logger.debug("View remains unresolved" + mediaTypeInfo);
return null;
}
}
}
Abstractview.java
public abstract class AbstractView extends WebApplicationObjectSupport implements View, BeanNameAware {
@Override
public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("View " + formatViewName() +
", model " + (model != null ? model : Collections.emptyMap()) +
(this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));
}
// 创建合并的输出模型
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
// 准备响应
prepareResponse(request, response);
// 渲染合并输出的模型数据,能将map、model里面的东西放置请求域中
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
protected Map<String, Object> createMergedOutputModel(@Nullable Map<String, ?> model,
HttpServletRequest request, HttpServletResponse response) {
@SuppressWarnings("unchecked")
Map<String, Object> pathVars = (this.exposePathVariables ?
(Map<String, Object>) request.getAttribute(View.PATH_VARIABLES) : null);
// Consolidate static and dynamic model attributes.
int size = this.staticAttributes.size();
size += (model != null ? model.size() : 0);
size += (pathVars != null ? pathVars.size() : 0);
Map<String, Object> mergedModel = CollectionUtils.newLinkedHashMap(size);
mergedModel.putAll(this.staticAttributes);
if (pathVars != null) {
mergedModel.putAll(pathVars);
}
if (model != null) {
// 将数据转移到了pathVars里面(Map)
mergedModel.putAll(model);
}
// Expose RequestContext?
if (this.requestContextAttribute != null) {
mergedModel.put(this.requestContextAttribute, createRequestContext(request, response, mergedModel));
}
return mergedModel;
}
// 渲染合并输出的模型数据,能将map、model里面的东西放置请求域中
protected HttpServletRequest getRequestToExpose(HttpServletRequest originalRequest) {
if (this.exposeContextBeansAsAttributes || this.exposedContextBeanNames != null) {
WebApplicationContext wac = getWebApplicationContext();
Assert.state(wac != null, "No WebApplicationContext");
return new ContextExposingHttpServletRequest(originalRequest, wac, this.exposedContextBeanNames);
}
// 获取到原生的HttpServletRequest
return originalRequest;
}
// Map<String,Object> map, Model model, HttpServletRequest request 都是可以给request域中放数据,
protected void exposeModelAsRequestAttributes(Map<String, Object> model,
HttpServletRequest request) throws Exception {
model.forEach((name, value) -> {
if (value != null) {
request.setAttribute(name, value);
}
else {
request.removeAttribute(name);
}
});
}
}
InternalResourceView.java
/**
* 视图解析
*/
public class InternalResourceView extends AbstractUrlBasedView {
@Override
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Expose the model object as request attributes.
// 暴露model作为请求域的属性
exposeModelAsRequestAttributes(model, request);
// Expose helpers as request attributes, if any.
exposeHelpers(request);
// Determine the path for the request dispatcher.
String dispatcherPath = prepareForRendering(request, response);
// Obtain a RequestDispatcher for the target resource (typically a JSP).
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
if (rd == null) {
throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
"]: Check that the corresponding file exists within your web application archive!");
}
// If already included or response already committed, perform include, else forward.
if (useInclude(request, response)) {
response.setContentType(getContentType());
if (logger.isDebugEnabled()) {
logger.debug("Including [" + getUrl() + "]");
}
rd.include(request, response);
}
else {
// Note: The forwarded resource is supposed to determine the content type itself.
if (logger.isDebugEnabled()) {
logger.debug("Forwarding to [" + getUrl() + "]");
}
rd.forward(request, response);
}
}
}
ServletModelAttributeMethodProcessor.java
public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodProcessor {
@Override
protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
// 拿到原生的request请求
ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class);
Assert.state(servletRequest != null, "No ServletRequest");
// 拿到binder
ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;
// 绑定
servletBinder.bind(servletRequest);
}
}
MethodParameter.java
public class MethodParameter {
public Class<?> getParameterType() {
Class<?> paramType = this.parameterType;
if (paramType != null) {
return paramType;
}
if (getContainingClass() != getDeclaringClass()) {
paramType = ResolvableType.forMethodParameter(this, null, 1).resolve();
}
if (paramType == null) {
paramType = computeParameterType();
}
this.parameterType = paramType;
return paramType;
}
}
BeanUtils.java
public abstract class BeanUtils {
public static boolean isSimpleProperty(Class<?> type) {
Assert.notNull(type, "'type' must not be null");
// isSimpleValueType判断是否简单类型
return isSimpleValueType(type) || (type.isArray() && isSimpleValueType(type.getComponentType()));
}
// 判断是否简单类型
public static boolean isSimpleValueType(Class<?> type) {
return (Void.class != type && void.class != type &&
(ClassUtils.isPrimitiveOrWrapper(type) ||
Enum.class.isAssignableFrom(type) ||
CharSequence.class.isAssignableFrom(type) ||
Number.class.isAssignableFrom(type) ||
Date.class.isAssignableFrom(type) ||
Temporal.class.isAssignableFrom(type) ||
URI.class == type ||
URL.class == type ||
Locale.class == type ||
Class.class == type));
}
}
ModelAttributeMethodProcessor.java
public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {
@Override
public boolean supportsParameter(MethodParameter parameter) {
// 是否有ModelAttribute注解
// 是否必输
// 是否简单属性
return (parameter.hasParameterAnnotation(ModelAttribute.class) ||
(this.annotationNotRequired && !BeanUtils.isSimpleProperty(parameter.getParameterType())));
}
@Override
@Nullable
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");
Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");
String name = ModelFactory.getNameForParameter(parameter);
// 是否有ModelAttribute注解
ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
if (ann != null) {
mavContainer.setBinding(name, ann.binding());
}
Object attribute = null;
BindingResult bindingResult = null;
// 判断之前的ModelAndViewContainer中是否有name的值
// 也就是mode.setAttribute();
if (mavContainer.containsAttribute(name)) {
attribute = mavContainer.getModel().get(name);
}
else {
// Create attribute instance
// 创建一个实例
try {
// attribute是一个空的POJO对象
attribute = createAttribute(name, parameter, binderFactory, webRequest);
}
catch (BindException ex) {
if (isBindExceptionRequired(parameter)) {
// No BindingResult parameter -> fail with BindException
throw ex;
}
// Otherwise, expose null/empty value and associated BindingResult
if (parameter.getParameterType() == Optional.class) {
attribute = Optional.empty();
}
else {
attribute = ex.getTarget();
}
bindingResult = ex.getBindingResult();
}
}
if (bindingResult == null) {
// Bean property binding and validation;
// skipped in case of binding failure on construction.
// WebDataBinderweb数据绑定器:将请求参数的值绑定到指定的Javabean里面
// attribute空对象 webRequest原生的HTTPSevletRequest请求
// 要把webRequest里面的数据封装到attribute空对象里面
// Http的请求里面的数据全部都是文本类型,需要利用请求转换器转换到相应的类型,封装到Javabean里面
// 请求转换器:binder.conversionService.converters.converters
// 例如:"java.lang.String -> java.lang.Float"
WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
if (binder.getTarget() != null) {
if (!mavContainer.isBindingDisabled(name)) {
// 利用反射获取webRequest里面的每一个参数值,找到Javabean里面的属性,把值封装到属性里面
bindRequestParameters(binder, webRequest);
}
validateIfApplicable(binder, parameter);
// 所有的类型和属性绑定完毕
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
// BindingResult中携带了数据校验的错误
throw new BindException(binder.getBindingResult());
}
}
// Value type adaptation, also covering java.util.Optional
if (!parameter.getParameterType().isInstance(attribute)) {
attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
}
bindingResult = binder.getBindingResult();
}
// Add resolved attribute and BindingResult at the end of the model
Map<String, Object> bindingResultModel = bindingResult.getModel();
mavContainer.removeAttributes(bindingResultModel);
mavContainer.addAllAttributes(bindingResultModel);
return attribute;
}
// 创建一个实例
protected Object createAttribute(String attributeName, MethodParameter parameter,
WebDataBinderFactory binderFactory, NativeWebRequest webRequest) throws Exception {
MethodParameter nestedParameter = parameter.nestedIfOptional();
Class<?> clazz = nestedParameter.getNestedParameterType();
Constructor<?> ctor = BeanUtils.getResolvableConstructor(clazz);
Object attribute = constructAttribute(ctor, attributeName, parameter, binderFactory, webRequest);
if (parameter != nestedParameter) {
attribute = Optional.of(attribute);
}
return attribute;
}
}
ServletRequestDataBinder.java
public class ServletRequestDataBinder extends WebDataBinder {
public void bind(ServletRequest request) {
// 获取到原生请求里面的所有的key和value,例如:age年龄、18岁
MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);
MultipartRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartRequest.class);
if (multipartRequest != null) {
bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
}
else if (StringUtils.startsWithIgnoreCase(request.getContentType(), "multipart/")) {
HttpServletRequest httpServletRequest = WebUtils.getNativeRequest(request, HttpServletRequest.class);
if (httpServletRequest != null) {
StandardServletPartUtils.bindParts(httpServletRequest, mpvs, isBindEmptyMultipartFiles());
}
}
// 添加绑定的值
addBindValues(mpvs, request);
// 绑定
doBind(mpvs);
}
}
ExtendedServletRequestDataBinder.java
public class ExtendedServletRequestDataBinder extends ServletRequestDataBinder {
@Override
protected void addBindValues(MutablePropertyValues mpvs, ServletRequest request) {
String attr = HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE;
@SuppressWarnings("unchecked")
Map<String, String> uriVars = (Map<String, String>) request.getAttribute(attr);
if (uriVars != null) {
uriVars.forEach((name, value) -> {
if (mpvs.contains(name)) {
if (logger.isWarnEnabled()) {
logger.warn("Skipping URI variable '" + name +
"' because request contains bind value with same name.");
}
}
else {
mpvs.addPropertyValue(name, value);
}
});
}
}
}
WebDataBinder.java
public class WebDataBinder extends DataBinder {
@Override
protected void doBind(MutablePropertyValues mpvs) {
checkFieldDefaults(mpvs);
checkFieldMarkers(mpvs);
adaptEmptyArrayIndices(mpvs);
super.doBind(mpvs);
}
}
DataBinder.java
public class DataBinder implements PropertyEditorRegistry, TypeConverter {
protected void doBind(MutablePropertyValues mpvs) {
checkAllowedFields(mpvs);
checkRequiredFields(mpvs);
// 应用属性
applyPropertyValues(mpvs);
}
protected void applyPropertyValues(MutablePropertyValues mpvs) {
try {
// Bind request parameters onto target object.
// 设置属性值
getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields());
}
catch (PropertyBatchUpdateException ex) {
// Use bind error processor to create FieldErrors.
for (PropertyAccessException pae : ex.getPropertyAccessExceptions()) {
getBindingErrorProcessor().processPropertyAccessException(pae, getInternalBindingResult());
}
}
}
}
AbstractPropertyAccessor.java
public abstract class AbstractPropertyAccessor extends TypeConverterSupport implements ConfigurablePropertyAccessor {
@Override
public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
throws BeansException {
List<PropertyAccessException> propertyAccessExceptions = null;
// 拿到所有的属性值
List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ?
((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));
if (ignoreUnknown) {
this.suppressNotWritablePropertyException = true;
}
try {
for (PropertyValue pv : propertyValues) {
// setPropertyValue may throw any BeansException, which won't be caught
// here, if there is a critical failure such as no matching field.
// We can attempt to deal only with less serious exceptions.
try {
setPropertyValue(pv);
}
catch (NotWritablePropertyException ex) {
if (!ignoreUnknown) {
throw ex;
}
// Otherwise, just ignore it and continue...
}
catch (NullValueInNestedPathException ex) {
if (!ignoreInvalid) {
throw ex;
}
// Otherwise, just ignore it and continue...
}
catch (PropertyAccessException ex) {
if (propertyAccessExceptions == null) {
propertyAccessExceptions = new ArrayList<>();
}
propertyAccessExceptions.add(ex);
}
}
}
finally {
if (ignoreUnknown) {
this.suppressNotWritablePropertyException = false;
}
}
// If we encountered individual exceptions, throw the composite exception.
if (propertyAccessExceptions != null) {
PropertyAccessException[] paeArray = propertyAccessExceptions.toArray(new PropertyAccessException[0]);
throw new PropertyBatchUpdateException(paeArray);
}
}
}
AbstractNestablePropertyAccessor.java
public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyAccessor {
@Override
public void setPropertyValue(PropertyValue pv) throws BeansException {
org.springframework.beans.AbstractNestablePropertyAccessor.PropertyTokenHolder tokens = (org.springframework.beans.AbstractNestablePropertyAccessor.PropertyTokenHolder) pv.resolvedTokens;
if (tokens == null) {
String propertyName = pv.getName();
org.springframework.beans.AbstractNestablePropertyAccessor nestedPa;
try {
// 利用反射赋值
nestedPa = getPropertyAccessorForPropertyPath(propertyName);
}
catch (NotReadablePropertyException ex) {
throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
"Nested property in path '" + propertyName + "' does not exist", ex);
}
tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
if (nestedPa == this) {
pv.getOriginalPropertyValue().resolvedTokens = tokens;
}
// 把真正的值set进去
nestedPa.setPropertyValue(tokens, pv);
}
else {
setPropertyValue(tokens, pv);
}
}
// 利用反射设置值
protected void setPropertyValue(org.springframework.beans.AbstractNestablePropertyAccessor.PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
if (tokens.keys != null) {
processKeyedProperty(tokens, pv);
}
else {
processLocalProperty(tokens, pv);
}
}
// 利用反射设置值
private void processLocalProperty(org.springframework.beans.AbstractNestablePropertyAccessor.PropertyTokenHolder tokens, PropertyValue pv) {
org.springframework.beans.AbstractNestablePropertyAccessor.PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
if (ph == null || !ph.isWritable()) {
if (pv.isOptional()) {
if (logger.isDebugEnabled()) {
logger.debug("Ignoring optional value for property '" + tokens.actualName +
"' - property not found on bean class [" + getRootClass().getName() + "]");
}
return;
}
if (this.suppressNotWritablePropertyException) {
// Optimization for common ignoreUnknown=true scenario since the
// exception would be caught and swallowed higher up anyway...
return;
}
throw createNotWritablePropertyException(tokens.canonicalName);
}
Object oldValue = null;
try {
// 拿到了真正的值18(age=18)
Object originalValue = pv.getValue();
Object valueToApply = originalValue;
if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
if (pv.isConverted()) {
valueToApply = pv.getConvertedValue();
}
else {
if (isExtractOldValueForEditor() && ph.isReadable()) {
try {
oldValue = ph.getValue();
}
catch (Exception ex) {
if (ex instanceof PrivilegedActionException) {
ex = ((PrivilegedActionException) ex).getException();
}
if (logger.isDebugEnabled()) {
logger.debug("Could not read previous value of property '" +
this.nestedPath + tokens.canonicalName + "'", ex);
}
}
}
// 字符串18要变成Integer18
valueToApply = convertForProperty(
tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());
}
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
}
// 转换完毕,把Integer18放入person里面
ph.setValue(valueToApply);
}
catch (TypeMismatchException ex) {
throw ex;
}
catch (InvocationTargetException ex) {
PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(
getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
if (ex.getTargetException() instanceof ClassCastException) {
throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
}
else {
Throwable cause = ex.getTargetException();
if (cause instanceof UndeclaredThrowableException) {
// May happen e.g. with Groovy-generated methods
cause = cause.getCause();
}
throw new MethodInvocationException(propertyChangeEvent, cause);
}
}
catch (Exception ex) {
PropertyChangeEvent pce = new PropertyChangeEvent(
getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
throw new MethodInvocationException(pce, ex);
}
}
@Nullable
private Object convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue,
@Nullable Object newValue, @Nullable Class<?> requiredType, @Nullable TypeDescriptor td)
throws TypeMismatchException {
Assert.state(this.typeConverterDelegate != null, "No TypeConverterDelegate");
try {
return this.typeConverterDelegate.convertIfNecessary(propertyName, oldValue, newValue, requiredType, td);
}
catch (ConverterNotFoundException | IllegalStateException ex) {
PropertyChangeEvent pce =
new PropertyChangeEvent(getRootInstance(), this.nestedPath + propertyName, oldValue, newValue);
throw new ConversionNotSupportedException(pce, requiredType, ex);
}
catch (ConversionException | IllegalArgumentException ex) {
PropertyChangeEvent pce =
new PropertyChangeEvent(getRootInstance(), this.nestedPath + propertyName, oldValue, newValue);
throw new TypeMismatchException(pce, requiredType, ex);
}
}
}