Spring Mvc 源代码之我见 二
上一篇简单介绍了spring mvc 的一些基本内容 和DispatcherServlet 的doc。这一篇将会继续写我对Spring Mvc 源代码的理解。直接上代码:
- /**
- * This implementation calls {@link #initStrategies}. --这里实现调用
- */
- @Override
//这里可以跟踪进,看到最终调用这个的是在:org\apache\tomcat\embed\tomcat-embed-core\8.5.23\tomcat-embed-core-8.5.23-sources.jar!\javax\servlet\GenericServlet.java中的init()方法中,而 GenericServlet.java 则是实现了Servlet接口的init()- protected void onRefresh(ApplicationContext context) {
- initStrategies(context);
- }
- /**
- * Initialize the strategy objects that this servlet uses.
- * <p>May be overridden in subclasses in order to initialize further strategy objects.
- */
- protected void initStrategies(ApplicationContext context) {
//上传文件流- initMultipartResolver(context);
//国际化- initLocaleResolver(context);
//主题- initThemeResolver(context);
//url映射- initHandlerMappings(context);
//适配器- initHandlerAdapters(context);
//处理异常- initHandlerExceptionResolvers(context);
//视图名转换- initRequestToViewNameTranslator(context);
//视图处理器- initViewResolvers(context);
- initFlashMapManager(context);
- }
先看下匹配器 initHandlerMappings(context);
- /**
- * Initialize the HandlerMappings used by this class.
- * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
- * we default to BeanNameUrlHandlerMapping.
- */
- private void initHandlerMappings(ApplicationContext context) {
- this.handlerMappings = null;
- if (this.detectAllHandlerMappings) { //是否检索所有的HandlerMapping 映射。默认是true
- // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
//查询所有的映射,包括祖先context的- Map<String, HandlerMapping> matchingBeans =
- BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
- if (!matchingBeans.isEmpty()) {
- this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
- // 放在一个排序的list中
- 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.
// 如果没有handlerMapping ,则使用默认的handlerMapping- if (this.handlerMappings == null) {
- this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
- if (logger.isDebugEnabled()) {
- logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
- }
- }
- }
最终会得到一个list:List<HandlerMapping>
——————————————————————
下面看 initHandlerAdapters
- /**
- * Initialize the HandlerAdapters used by this class.
- * <p>If no HandlerAdapter beans are defined in the BeanFactory for this namespace,
- * we default to SimpleControllerHandlerAdapter.
- */
- private void initHandlerAdapters(ApplicationContext context) {
- this.handlerAdapters = null;
- if (this.detectAllHandlerAdapters) {
- // Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
- Map<String, HandlerAdapter> matchingBeans =
- BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
- if (!matchingBeans.isEmpty()) {
- this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());
- // We keep HandlerAdapters in sorted order.
- AnnotationAwareOrderComparator.sort(this.handlerAdapters);
- }
- }
- else {
- try {
- HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
- this.handlerAdapters = Collections.singletonList(ha);
- }
- catch (NoSuchBeanDefinitionException ex) {
- // Ignore, we'll add a default HandlerAdapter later.
- }
- }
- // Ensure we have at least some HandlerAdapters, by registering
- // default HandlerAdapters if no other adapters are found.
- if (this.handlerAdapters == null) {
- this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
- if (logger.isDebugEnabled()) {
- logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
- }
- }
- }
从代码可以看出,这里的代码和 initHandlerMappings 非常像,都是把bean添加到一个list里面,唯一不同的是类型而已。
———————————————————————————————————————————————————
DispatcherServlet 处理请求方法,在 doService(HttpServletRequest request, HttpServletResponse response) 。在DispatcherServlet 的父类FrameworkServlet的processRequest 中调用了这个方法。(这里又是一个模板方法模式)。doService(HttpServletRequest request, HttpServletResponse response) 源代码如下:
- /**
- * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
- * for the actual dispatching.
- */
//实际调用DispatcherServlet- @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<String, Object>();
- 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.
// 使处理器和视图都可以使用object- 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());
- 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);
- }
- }
- }
- }
- /**
- * 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 {
- processedRequest = checkMultipart(request);
- multipartRequestParsed = (processedRequest != request);
- // Determine handler for the current request.
//查找匹配的Controller 、方法、参数、返回值、异常等消息。处理的方法是迭代 initHandlerMapping(context) 里面的注册的mapping,这个是放在一个list里面- mappedHandler = getHandler(processedRequest);
- if (mappedHandler == null || mappedHandler.getHandler() == null) {
- noHandlerFound(processedRequest, response);
- return;
- }
- // Determine handler adapter for the current request.
- HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); //确定请求调用的HandlerAdapter。我们自定义的HandlerAdapter,也是在这里被获取到。
- // Process last-modified header, if supported by the handler.
- String method = request.getMethod(); //获取报文里面的方法名称
- boolean isGet = "GET".equals(method); //是否是GET调用
- if (isGet || "HEAD".equals(method)) {
- long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); //查找url中对应的方法
- if (logger.isDebugEnabled()) {
- logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
- }
- 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;
- }
//确定view- 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);
- }
//解释模型和者视图(ModelAndView),或者是异常- 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);
- }
- }
- }
- }
从这里看出,基本流程就是:查到需要调用的方法–> 执行方法 —>返回模型和视图(ModelAndView)或者异常 –> 解释返回的模型和视图
ha.handle(processedRequest, response, mappedHandler.getHandler()) 的源代码如下:
- @Override
- protected ModelAndView handleInternal(HttpServletRequest request,
- HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
- ModelAndView mav;
- checkRequest(request); //检查是否是支持的http请求(GET、POST)和 需要session 支持
- // 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;
- }
- /**
- * Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView}
- * if view resolution is required.
- * @since 4.2
- * @see #createInvocableHandlerMethod(HandlerMethod)
- */
- protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
- HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
- ServletWebRequest webRequest = new ServletWebRequest(request, response); //获取url相关
- try {
- WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
- ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
- ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); //获取要Controller、method、args、return type 等信息
- invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
- 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);
- }
- invocableMethod.invokeAndHandle(webRequest, mavContainer); //真正地使用反射来执行方法,并返回值
- if (asyncManager.isConcurrentHandlingStarted()) {
- return null;
- }
- return getModelAndView(mavContainer, modelFactory, webRequest); //返回ModelAndView
- }
- finally {
- webRequest.requestCompleted();
- }
- }
invocableMethod.invokeAndHandle(webRequest, mavContainer) 的代码如下:
- /**
- * Invoke the method and handle the return value through one of the
- * configured {@link HandlerMethodReturnValueHandler}s.
- * @param webRequest the current request
- * @param mavContainer the ModelAndViewContainer for this request
- * @param providedArgs "given" arguments matched by type (not resolved)
- */
- public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
- Object... providedArgs) throws Exception {
- 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);
- 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;
- }
- }
- /**
- * Invoke the method after resolving its argument values in the context of the given request.
- * <p>Argument values are commonly resolved through {@link HandlerMethodArgumentResolver}s.
- * The {@code providedArgs} parameter however may supply argument values to be used directly,
- * i.e. without argument resolution. Examples of provided argument values include a
- * {@link WebDataBinder}, a {@link SessionStatus}, or a thrown exception instance.
- * Provided argument values are checked before argument resolvers.
- * @param request the current request
- * @param mavContainer the ModelAndViewContainer for this request
- * @param providedArgs "given" arguments matched by type, not resolved
- * @return the raw value returned by the invoked method
- * @exception Exception raised if no suitable argument resolver can be found,
- * or if the method raised an exception
- */
- public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
- Object... providedArgs) throws Exception {
- Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); //获取参数
- if (logger.isTraceEnabled()) {
- logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
- "' with arguments " + Arrays.toString(args));
- }
- Object returnValue = doInvoke(args); //执行方法
- if (logger.isTraceEnabled()) {
- logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
- "] returned [" + returnValue + "]");
- }
- return returnValue;
- }
- /**
- * Invoke the handler method with the given argument values.
- */
- protected Object doInvoke(Object... args) throws Exception {
- ReflectionUtils.makeAccessible(getBridgedMethod());
- try {
- return getBridgedMethod().invoke(getBean(), args); //使用反射执行方法
- }
- catch (IllegalArgumentException ex) {
- assertTargetBean(getBridgedMethod(), getBean(), args);
- String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
- throw new IllegalStateException(getInvocationErrorMessage(text, args), ex);
- }
- catch (InvocationTargetException ex) {
- // Unwrap for HandlerExceptionResolvers ...
- Throwable targetException = ex.getTargetException();
- if (targetException instanceof RuntimeException) {
- throw (RuntimeException) targetException;
- }
- else if (targetException instanceof Error) {
- throw (Error) targetException;
- }
- else if (targetException instanceof Exception) {
- throw (Exception) targetException;
- }
- else {
- String text = getInvocationErrorMessage("Failed to invoke handler method", args);
- throw new IllegalStateException(text, targetException);
- }
- }
- }
———————————————————————————————
继续跟进 getModelAndView(mavContainer, modelFactory, webRequest) 方法,源代码如下:
- private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
- ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
- modelFactory.updateModel(webRequest, mavContainer);
- if (mavContainer.isRequestHandled()) {
- return null;
- }
- ModelMap model = mavContainer.getModel();
- 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);
- RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
- }
- return mav;
- }
- ModelAndView 代码如下:
- public class ModelAndView {
- /** View instance or view name String */
- private Object view;
- /** Model Map */
- private ModelMap model;
- /** Optional HTTP status for the response */
- private HttpStatus status;
- /** Indicates whether or not this instance has been cleared with a call to {@link #clear()} */
- private boolean cleared = false;
- //************************ 省略
- }
再返回看下解释视图和模型或者异常的方法 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException) ,源代码如下:
- /**
- * Handle the result of handler selection and handler invocation, which is
- * either a ModelAndView or an Exception to be resolved to a ModelAndView.
- */
- private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
- HandlerExecutionChain mappedHandler, ModelAndView mv, 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(mv, request, response); //解释、渲染视图和模型
- if (errorView) {
- WebUtils.clearErrorRequestAttributes(request);
- }
- }
- else {
- if (logger.isDebugEnabled()) {
- logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
- "': assuming HandlerAdapter completed request handling");
- }
- }
- if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
- // Concurrent handling started during a forward
- return;
- }
- if (mappedHandler != null) {
- mappedHandler.triggerAfterCompletion(request, response, null);
- }
- }
- /**
- * Render the given ModelAndView.
- * <p>This is the last stage in handling a request. It may involve resolving the view by name.
- * @param mv the ModelAndView to render
- * @param request current HTTP servlet request
- * @param response current HTTP servlet response
- * @throws ServletException if view is missing or cannot be resolved
- * @throws Exception if there's a problem rendering the view
- */
- 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.resolveLocale(request);
- response.setLocale(locale);
- View view;
- if (mv.isReference()) { //引用视图
- // We need to resolve the view name.
- view = resolveViewName(mv.getViewName(), 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.isDebugEnabled()) {
- logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
- }
- 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 + "] in DispatcherServlet with name '" +
- getServletName() + "'", ex);
- }
- throw ex;
- }
- }
—————————————————————————————————————————
以上就是我的基本分析,当然还有很多细节没有看,只是看了基本的流程和核心代码。如果有错,请大神指正。