当spring管理的对象的方法或者参数出现了注解@ModelAttribute时候,意味着这个属性会被注入java
@ModelAttribute public Book get(@RequestParam(required=false) String id) { Book entity = null; if (StringUtils.isNotBlank(id)){ entity = bookService.get(id); } if (entity == null){ entity = new Book(); } return entity; }
当这个类中全部方法被调用以前这个方法都会被执行放入web
ModelAndViewContainer
这个容器中去,当对应的方法被执行的时候若是没有传入参数会去这个容器中找到匹配参数继而传入到方法调用spring
@RequestMapping(value = "form") public String form(Book book, Model model) { model.addAttribute("book", book); return "ibook/book/bookForm"; }
当这个方法再被调用时候以前查出来的Book对象会天然被传入,而前台并未传入,此方法适合修改一个对象的操做如update,只须要传入ModelAttribute对应方法的参数便可session
请求流程图以下:app
当请求到RequestMappingHandlerAdapter对象的invokeHandleMethod方法async
private ModelAndView invokeHandleMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory); ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); //初始化ModelAttribute注解方法 modelFactory.initModel(webRequest, mavContainer, requestMappingMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); asyncWebRequest.setTimeout(this.asyncRequestTimeout); final 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 + "]"); } requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result); } requestMappingMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } return getModelAndView(mavContainer, modelFactory, webRequest); }
ModelFactory的initModel以下ide
public void initModel(NativeWebRequest request, ModelAndViewContainer mavContainer, HandlerMethod handlerMethod) throws Exception { //抽取出目标类的全部方法 Map<String, ?> attributesInSession = this.sessionAttributesHandler.retrieveAttributes(request); mavContainer.mergeAttributes(attributesInSession); //设置ModelAttribute注解的值 invokeModelAttributeMethods(request, mavContainer); for (String name : findSessionAttributeArguments(handlerMethod)) { if (!mavContainer.containsAttribute(name)) { Object value = this.sessionAttributesHandler.retrieveAttribute(request, name); if (value == null) { throw new HttpSessionRequiredException("Expected session attribute '" + name + "'"); } mavContainer.addAttribute(name, value); } } }
invokeModelAttributeMethods方法以下:函数
private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer mavContainer) throws Exception { for (InvocableHandlerMethod attrMethod : this.attributeMethods) { //获取含有注解的对应方法名 String modelName = attrMethod.getMethodAnnotation(ModelAttribute.class).value(); if (mavContainer.containsAttribute(modelName)) { continue; } Object returnValue = attrMethod.invokeForRequest(request, mavContainer); if (!attrMethod.isVoid()){ String returnValueName = getNameForReturnValue(returnValue, attrMethod.getReturnType()); if (!mavContainer.containsAttribute(returnValueName)) { mavContainer.addAttribute(returnValueName, returnValue); } } } }
此时便把注解解析完成值都放入到了mavContainer容器中。ui
此时回到执行目标方法流程图既是:RequestMappingHandlerAdapter的invokeHandleMethod方法this
requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
到ServletInvocableHandlerMethod的invokeAndHandle
public final void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { //执行目标函数 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); if (returnValue == null) { if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) { mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(this.responseReason)) { mavContainer.setRequestHandled(true); return; } mavContainer.setRequestHandled(false); try { 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; } }
到InvokableHandlerMethod的invokeForRequest
public final Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { StringBuilder sb = new StringBuilder("Invoking ["); sb.append(getBeanType().getSimpleName()).append("."); sb.append(getMethod().getName()).append("] method with arguments "); sb.append(Arrays.asList(args)); logger.trace(sb.toString()); } Object returnValue = invoke(args); if (logger.isTraceEnabled()) { logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]"); } return returnValue; }