栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

《看透SpringMVC源代码分析与实践》SpringMVC组件详解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

《看透SpringMVC源代码分析与实践》SpringMVC组件详解

目录

一、HandlerMapping

  • 继承体系
  • AbstractHandlerMapping
  • AbstractUrlHandlerMapping系列
  • AbstractHandlerMethodMapping系列

二、HandlerAdapter

  • RequestMappingHandlerAdapter概述
  • RequestMappingHandlerAdapter自身结构
  • 总结

三、ViewResolver

四、RequestToViewTranslator

五、HandlerExceptionResolver

六、MultipartResolver

  • StandardServletMultipartResolver

七、SpringMVC原理总结

  • 原理总结
  • 跟踪一个请求处理流程详细过程

一、HandlerMapping 1、继承体系


可以看到HandlerMapping家族的成员可以分为两支,其下第一个抽象类为AbstractHandlerMapping

  • 一支继承AbstractUrlHandlerMapping
  • 一支继承AbstractHandlerMethodMapping
2、AbstractHandlerMapping

概述

  • 是HandlerMapping的抽象实现,下面所有的XxxHandlerMapping都继承他
  • 采用模板模式设计了HandlerMapiing实现的整体结构,子类只需要通过模板方法提供一些初始值或者具体的算法即可,首先使用一个抽象类实现采用模板模式进行整体设计,然后子类通过实现模板方法具体完成业务。
  • HandlerMapping的作用是根据request查找Handler和Interceptors,获取Handler的过程通过模板方法getHandlerInternal交给了子类。
  • AbstractHandlerMapping保存了所有配置的Interceptor,在获取到Handler之后会自己根据从request提取的lookupPath将相应的Interceptors装配上去
  • 子类可以通过getHandlerinternal方法设置自己的Interceptor,返回值类型为Object
2.1创建AbstractHandlerMapping之器

概述

  • 先看类继承实现public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered, BeanNameAware {}
  • 父类WebApplicationObjectSupport ,初始化会自动调用模板方法initApplicationContext,,也就是子类AbstractHandlerMapping的入口方法
  • AbstractHandlerMapping的创建就是在initApplicationContext方法里面实现的
// WebApplicationObjectSupport 模板方法,调用子类的
protected void initApplicationContext(ApplicationContext context) {
        super.initApplicationContext(context);
        if (this.servletContext == null && context instanceof WebApplicationContext) {
            this.servletContext = ((WebApplicationContext)context).getServletContext();
            if (this.servletContext != null) {
                this.initServletContext(this.servletContext);
            }
        }

    }
// AbstractHandlerMapping 的 入口方法
 protected void initApplicationContext() throws BeansException {
 		// 1. 模板方法,用于给子类提供添加、修改Interceptors的入口,不过现有的SpringMVC没有使用
        this.extendInterceptors(this.interceptors);
        // 2. 将SpringMVC容器及父容器中 所有的 MappedInterceptor类型的Bean添加到adaptedInterceptors成员属性
        this.detectMappedInterceptors(this.adaptedInterceptors);
        // 3. 初始化Interceptor,具体的内容是将 全部interceptors所包含的对象按照类型添加到装配好的adaptedInterceptors成员属性
        this.initInterceptors();
    }

// 成员属性
// 全部的Interceptors,作为汇总列表使用
private final List interceptors = new ArrayList();
// 装配好的Interceptors列表
private final List adaptedInterceptors = new ArrayList();



// 2. detectMappedInterceptors()
protected void detectMappedInterceptors(List mappedInterceptors) {
        mappedInterceptors.addAll(BeanFactoryUtils.beansOfTypeIncludingAncestors(this.obtainApplicationContext(), MappedInterceptor.class, true, false).values());
    }

// 3. initInterceptors()
  protected void initInterceptors() {
        if (!this.interceptors.isEmpty()) {
            for(int i = 0; i < this.interceptors.size(); ++i) {
                Object interceptor = this.interceptors.get(i);
                if (interceptor == null) {
                    throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
                }

                this.adaptedInterceptors.add(this.adaptInterceptor(interceptor));
            }
        }

    }

 

成员属性概述

  • List interceptors:用于配置SpringMVC的拦截器,有两种设置方式①注册HandlerMapping时通过属性设置②通过子类的extendInterceptors钩子方法进行设置。
    并不会直接使用,而是通过initInterceptors()方法装配到adaptedInterceptors()才能使用。

  • List adaptedInterceptors:这种类型的Interceptor不需要在进行匹配,在getHandler中会全部添加到返回值HnadlerExecutionChain里面,或者是使用时与请求的url进行匹配,从detectMappedInterceptors()方法获取添加到HnadlerExecutionChain里面

  • 2.2AbstractHandlerMapping之用

    HandlerMapping是通过getHandler方法处理处理器Handler和Interceptor的,实现分为两部分

    • 第一部分:找Handler
    • 第二部分:添加Interceptors
    @Nullable
        public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        	// 第一部分,找Handler
    		// 1. 模板方法,子类需要做的事情
            Object handler = this.getHandlerInternal(request);
            if (handler == null) {
            	// 2. 没有找到,使用默认的,保存早该类的成员属性defaultHandler,可以在配置HandlerMapping的时候配置,也可以在子类配置
                handler = this.getDefaultHandler();
            }
    
            if (handler == null) {
                return null;
            } else {
            	// 3. 找到是String类型,则根据名字去SpringMVC的容器查找响应的Bean
                if (handler instanceof String) {
                    String handlerName = (String)handler;
                    handler = this.obtainApplicationContext().getBean(handlerName);
                }
    
    			// 第二部分
    			// 1. 根据Handler创建 executionChain  执行链对象
                HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("Mapped to " + handler);
                } else if (this.logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
                    this.logger.debug("Mapped to " + executionChain.getHandler());
                }
    
                if (this.hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
                    CorsConfiguration config = this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null;
                    CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
                    config = config != null ? config.combine(handlerConfig) : handlerConfig;
                    executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
                }
    
                return executionChain;
            }
        }
    
    
    // 1. getHandlerExecutionChain()方法
    protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    		// 根据handler创建chain对象
            HandlerExecutionChain chain = handler instanceof HandlerExecutionChain ? (HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
            String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
            // 之前装配好的拦截器
            Iterator var5 = this.adaptedInterceptors.iterator();
    
            while(var5.hasNext()) {
                HandlerInterceptor interceptor = (HandlerInterceptor)var5.next();
                if (interceptor instanceof MappedInterceptor) {
                    MappedInterceptor mappedInterceptor = (MappedInterceptor)interceptor;
                    if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                        chain.addInterceptor(mappedInterceptor.getInterceptor());
                    }
                } else {
                    chain.addInterceptor(interceptor);
                }
            }
    
            return chain;
        }
    
    3、AbstractUrlHandlerMapping系列

    概述

    • 该系列的类都继承AbstractUrlHandlerMapping,它是根据url匹配的。
    • 此系列的大致原理是将url和对应的handler保存在一个Map中,在getHandlerInternal方法使用url从Map中获Handler
    • AbstractUrlHandlerMapping完成了url查找handler的过程,对于map的初始化工作交给子类完成,这里的map就是定义在AbstractUrlHandlerMapping的成员变量handlerMap
    • 另外还定义了处理/请求的rootHandler,定义在成员变量private Object rootHandler

    主要问题就是

    • 怎么获取handler的?
    • 这个Map是由子类怎么创建的?
    3.1根据URL获取Handler

    获取handler的入口是在子类 实现AbstractHandlerMapping模板方法getHandlerInternal()里面,也就是AbstractUrlHandlerMapping的getHandlerInternal()

     @Nullable
        protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
            String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
            request.setAttribute(LOOKUP_PATH, lookupPath);
            // 一、用于使用lookupPath从Map找Handler,不过很多时候不能直接从Map中get到,
            // 1. 因为很多的Handler都是使用Pattern的匹配模式,如/xiaosi
    // 不设置的的话,默认从AbstractHandlerMethodAdapter中直接传入false,不对请求方式限制
    	@Nullable
    private Set supportedMethods;
    
    protected final void checkRequest(HttpServletRequest request) throws ServletException {
    		// Check whether we should support the request method.
    		String method = request.getMethod();
    		// 默认不检查,请求的类型是否支持
    		if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {
    			throw new HttpRequestMethodNotSupportedException(method, this.supportedMethods);
    		}
    
    		// Check whether a session is required.
    		// 默认也是不检查,如果session是必须存在的,判断session是否真实存在
    		if (this.requireSession && request.getSession(false) == null) {
    			throw new HttpSessionRequiredException("Pre-existing session required but none found");
    		}
    	}
    

    执行请求处理

    1. 首先创建ServletWebRequest对象
      // 在ArgumentResolver解析参数时候的request就是这个对象,处理器需要HttpServletRequest,这是ArgumentResolver就会转换设置

    2. 初始化3个变量
      // 2.1用于参数跟String之间的类型转换,ModelFactory 刷新也会用到它:// 将符合条件注释了@InitBinder的方法找出来,这些方法主要用于处理参数
      // 2.2主要是处理Model的,主要包含两个功能,1. 在处理器具体处理之前对Model初始化, 2. 再处理完成请求后对Model参数更新
      - 将原来的SessionAttributes的值设置的Model
      - 执行相应注释@ModelAttribute的方法并将值设置到Model
      - 处理器注释了了@ModelAttribute的参数同时在SessionAttributes中设置了,而且在mvcCobtainer中没有,则将全部的SessionAttributes中查找并设置进去

    3. 创建invocableMethod 真正的执行者:继承HandlerMethod,并且可以直接执行,实际请求的处理就是通过它执行的,参数绑定、处理请求、返回值都是这里完成

    4. 将参数解析组件、返回值处理组件 等组件设置进去:也就是子类实现完成之后的组件,对应之前创建之器声明的哪些保存在成员变量的组件

    5. 新建mavContainer:保存Model和View,请求参数传递进去

    执行

    // 调用方法2invokeHandlerMethod():执行请求处理
    
    
    @Nullable
    	protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
    			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    		// 1. 首先创建ServletWebRequest对象
    		// 在ArgumentResolver解析参数时候的request就是这个对象,处理器需要HttpServletRequest,这是ArgumentResolver就会转换设置
    		ServletWebRequest webRequest = new ServletWebRequest(request, response);
    		try {
    			// 2. 初始化3个变量
    			// 2.1用于参数跟String之间的类型转换,ModelFactory 刷新也会用到它
    			// 将符合条件注释了@InitBinder的方法找出来,这些方法主要用于处理参数
    			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
    			// 2.2主要是处理Model的,主要包含两个功能,
    			//    1. 在处理器具体处理之前对Model初始化
    			//    2. 再处理完成请求后对Model参数更新
    					//- 将原来的SessionAttributes的值设置的Model
    					//- 执行相应注释@ModelAttribute的方法并将值设置到Model
    					//- 处理器注释了了@ModelAttribute的参数同时在SessionAttributes中设置了,而且在mvcCobtainer中没有纸则将全部的SessionAttributes中查找并设置进去
    
    
    			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
    			// 2.3继承HandlerMethod,并且可以直接执行,实际请求的处理就是通过它执行的,参数绑定、处理请求、返回值都是这里完成
    			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
    			// 3.将参数解析组件、返回值处理组件 等组件设置进去
    			if (this.argumentResolvers != null) {
    				invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
    			}
    			if (this.returnValueHandlers != null) {
    				invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
    			}
    			invocableMethod.setDataBinderFactory(binderFactory);
    			invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
    			
    			// 4. 新建mavContainer:保存Model和View,请求参数传递进去
    			// 4.1并将相应参数设置进去
    			
    			
    			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);
    			}
    			// 4.2执行请求
    			invocableMethod.invokeAndHandle(webRequest, mavContainer);
    			if (asyncManager.isConcurrentHandlingStarted()) {
    				return null;
    			}
    			// 4.3请求处理完成完成进行一些后置处理
    			return getModelAndView(mavContainer, modelFactory, webRequest);
    		}
    		finally {
    			webRequest.requestCompleted();
    		}
    	}
    
    // 4.2执行请求
    
    	public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
    			Object... providedArgs) throws Exception {
    		//1. 执行
    		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    		setResponseStatus(webRequest);
    		
    		// 2. 返回值处理
    		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) {
    			if (logger.isTraceEnabled()) {
    				logger.trace(formatErrorForReturnValue(returnValue), ex);
    			}
    			throw ex;
    		}
    	}
    
    // 真正执行
     @Nullable
        public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
        	//1. 准备方法参数
            Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Arguments: " + Arrays.toString(args));
            }
    		// 2. doInvoke()反射执行,整个执行的核心
            return this.doInvoke(args);
        }
    
    //1.  获取准备处理器方法参数
     protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
     		// 获取方法的参数,在HandlerMethod中,子类会自动同步到本类的成员变量
            MethodParameter[] parameters = this.getMethodParameters();
            if (ObjectUtils.isEmpty(parameters)) {
                return EMPTY_ARGS;
            } else {
            // 保存解析出参数的值
                Object[] args = new Object[parameters.length];
    
                for(int i = 0; i < parameters.length; ++i) {
                    MethodParameter parameter = parameters[i];
                    // 给parameter设置参数名解析器
                    parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
                    args[i] = findProvidedArgument(parameter, providedArgs);
                    if (args[i] == null) {
                        if (!this.resolvers.supportsParameter(parameter)) {
                            throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
                        }
    
                        try {
                        // 使用resolvers,也就是子类实现的解析器解析
                            args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
                        } catch (Exception var10) {
                            if (this.logger.isDebugEnabled()) {
                                String exMsg = var10.getMessage();
                                if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
                                    this.logger.debug(formatArgumentError(parameter, exMsg));
                                }
                            }
    
                            throw var10;
                        }
                    }
                }
    
                return args;
            }
        }
    
    	// 2. 真正反射执行
        @Nullable
        protected Object doInvoke(Object... args) throws Exception {
            ReflectionUtils.makeAccessible(this.getBridgedMethod());
    
            try {
            	// 真正反射执行
                return this.getBridgedMethod().invoke(this.getBean(), args);
            } catch (IllegalArgumentException var4) {
                this.assertTargetBean(this.getBridgedMethod(), this.getBean(), args);
                String text = var4.getMessage() != null ? var4.getMessage() : "Illegal argument";
                throw new IllegalStateException(this.formatInvokeError(text, args), var4);
            } catch (InvocationTargetException var5) {
                Throwable targetException = var5.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 {
                    throw new IllegalStateException(this.formatInvokeError("Invocation failure", args), targetException);
                }
            }
        }
    
    // 4.3请求处理完成完成进行一些后置处理,拿到ModelAndView返回
    @Nullable
    	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 flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
    			HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
    			if (request != null) {
    				RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
    			}
    		}
    		return mav;
    	}
    

    注解@SessionAttributes概述

    • 主要用在处理器类上,用于在多个请求之间传递参数,类似于Session的Attribute,但是也不一样,前者只适用暂时的传递,而不是长期的保存,长期应该适用Sesssion的setAttribute()保存
    • 主要用法:1、设置了该注解的参数在视图中通过request、session的的getAttribute()获取,2、在后面请求返回的视图中通过session的getAttribute或者Model获取,3、自动将参数设置到后面请求处理器的Model或者@ModelAttribute注解的参数
    • 设置方法:1、需要满足在@SessionAttribute注解设置参数名、类型,2、在处理器中将参数设置到Model,之后会自动的有ModelFactory完成更新,使用完毕之后可以调用SessionStatus.setComplete()清除,这对已经存入session的参数。


    小结

    • SessionAttributesHandler:用来处理@SessionAttributes注释的参数,做一些宏观的事情,如那个Handler可以缓存哪些参数,某个参数再当前的SessionAttribues中是否存在
    • SessionAttributeStore:并不是保存数据的容器,而是工具,单个参数的处理操作,可以临时当做缓存处理,容器默认为Session,默认实现DefaultSessionAttributeStore使用ServletWebRequest将参数设置到Session中,具体是在ModelFactory使用
    // 主要是针对某个处理器的@SessionAttribute处理
    public class SessionAttributesHandler {
    	// 设置的注解value
        private final Set attributeNames = new HashSet();
        // 类型
        private final Set> attributeTypes = new HashSet();
        // 全部的values
        private final Set knownAttributeNames = Collections.newSetFromMap(new ConcurrentHashMap(4));
        // 操作单个参数的工具,SessionAttributeStore,在session和model之间
        private final SessionAttributeStore sessionAttributeStore;
    
        public SessionAttributesHandler(Class handlerType, SessionAttributeStore sessionAttributeStore) {
            Assert.notNull(sessionAttributeStore, "SessionAttributeStore may not be null");
            this.sessionAttributeStore = sessionAttributeStore;
            SessionAttributes ann = (SessionAttributes)AnnotatedElementUtils.findMergedAnnotation(handlerType, SessionAttributes.class);
            if (ann != null) {
                Collections.addAll(this.attributeNames, ann.names());
                Collections.addAll(this.attributeTypes, ann.types());
            }
    
            this.knownAttributeNames.addAll(this.attributeNames);
        }
    
        public boolean hasSessionAttributes() {
            return !this.attributeNames.isEmpty() || !this.attributeTypes.isEmpty();
        }
    
        public boolean isHandlerSessionAttribute(String attributeName, Class attributeType) {
            Assert.notNull(attributeName, "Attribute name must not be null");
            if (!this.attributeNames.contains(attributeName) && !this.attributeTypes.contains(attributeType)) {
                return false;
            } else {
                this.knownAttributeNames.add(attributeName);
                return true;
            }
        }
    
        public void storeAttributes(WebRequest request, Map attributes) {
            attributes.forEach((name, value) -> {
                if (value != null && this.isHandlerSessionAttribute(name, value.getClass())) {
                    this.sessionAttributeStore.storeAttribute(request, name, value);
                }
    
            });
        }
    
        public Map retrieveAttributes(WebRequest request) {
            Map attributes = new HashMap();
            Iterator var3 = this.knownAttributeNames.iterator();
    
            while(var3.hasNext()) {
                String name = (String)var3.next();
                Object value = this.sessionAttributeStore.retrieveAttribute(request, name);
                if (value != null) {
                    attributes.put(name, value);
                }
            }
    
            return attributes;
        }
    
        public void cleanupAttributes(WebRequest request) {
            Iterator var2 = this.knownAttributeNames.iterator();
    
            while(var2.hasNext()) {
                String attributeName = (String)var2.next();
                this.sessionAttributeStore.cleanupAttribute(request, attributeName);
            }
    
        }
    
        @Nullable
        Object retrieveAttribute(WebRequest request, String attributeName) {
            return this.sessionAttributeStore.retrieveAttribute(request, attributeName);
        }
    }
    
    


    2.3ModelAndViewContainer
    • ModelAndViewContainer:承担整个过程中数据传递工作,除了保存Model和View 外还有一些别的功能,
      • 内有属性defaultModel:主要用于封装默认Model数据,就是默认使用Model和ModelAndView时候,ArgumentResolver会传入defaultModel,继承了ModelMap实现了Model接口
      • 内有属性redirectModel:主要用于封装重定向之后Model的数据
      • 内有属性view:可以是逻辑、实际视图
      • 内有属性requestHandler:主要是标志请求是否处理完返回response,是就不在往下处理,直接返回。有@ResposeBody注解的方法或者返回值为Httpentity的都会将该属性设置为true
    2.4InvocableHandlerMethod执行者

    先看父类HandlerMethod

    • 封装Handler和具体处理请求的Method,分别对应bean和method属性,除了这两个还有其他三个属性
    • beanFactory:新建HandlerMethod时候传入的Handler是String类型,需要获取Bean
    • bridgeMethod:如果Method是bridgeMethod则设置为原有方法
    • parameters:请求方法的参数集合,具体元素为MethodParameter类型(内部类),一个对象代表一个方法的请求参数

    在父类的基础上

    • 增加了方法执行功能
    • 相应的增加了参数解析、处理返回值等
    • 在父类的基础上加了调用的功能,可以直接调用内部属性method对应的bridgeMethod
    • 增加了属性dataBinderFactory(参数解析器使用)、argumentResolvers(解析参数)、paramaterNameDiscover(获取参数名)

    MethodParameter 请求方法参数类的成员属性

    另外封装参数的内部类是ReturnValueMethodParameter,主要负责方法返回的参数

    • 继承HandlerMethodParameter
    • 使用的方法都是bridgeMethod,桥方法,为了处理父类泛型的问题,不涉及泛型就是原方法
    • 返回值使用的parameterIndex都是-1

    子类ServletInvocableHandlerMethod,在父类的基础上增加了3个功能

    • 对@ResponseStatus的支持
    • 对返回值的处理:HandlerMethodReturnValueHandler类型的成员变量
    • 对一部处理结果的处理
    2.5HandlerMethodArgumentResolver

    概述

    • 是用来处理器解析参数的,主要用在上面的InvocableHandlerMethod中,每个Resolver对应一种类型的参数,也就是创建RequestHandelrAdapter时候声明的那些待子类实现的XxxResolver组件的父接口
    • 每个实现类对应一种类型的参数,命名大致两种
      • XxxMethodArgumentResolver
      • XxxMethodProcess:另外包含处理响应类型的返回值
    • HandlerMethodArgumentResolverComposite内部可以防多个XxxResolver

    解析器介绍

    1、解析Model类型参数的ModelMethodProcess解析器

    既可以解析参数,也可哟处理返回值

    public class ModelMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {
        public ModelMethodProcessor() {
        }
    	
    	// 1. 判断如果是Model类型就可以
        public boolean supportsParameter(MethodParameter parameter) {
            return Model.class.isAssignableFrom(parameter.getParameterType());
        }
    
        @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");
            // 2. 直接从 mavContainer 获取 值可能来自FlushMap、SessionAttribute中
            return mavContainer.getModel();
        }
    
        public boolean supportsReturnType(MethodParameter returnType) {
            return Model.class.isAssignableFrom(returnType.getParameterType());
        }
    
        public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
            if (returnValue != null) {
                if (returnValue instanceof Model) {
                    mavContainer.addAllAttributes(((Model)returnValue).asMap());
                } else {
                    throw new UnsupportedOperationException("Unexpected return type: " + returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
                }
            }
        }
    }
    
    
    2、解析@PathVariable参数类型的PathVariableMethodArgumentResolver解析器

    先看父类AbstractNamedValueMethodArgumentResolver

     @Nullable
        public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
            AbstractNamedValueMethodArgumentResolver.NamedValueInfo namedValueInfo = this.getNamedValueInfo(parameter);
            MethodParameter nestedParameter = parameter.nestedIfOptional();
            
            Object resolvedName = this.resolveStringValue(namedValueInfo.name);
            if (resolvedName == null) {
                throw new IllegalArgumentException("Specified name must not resolve to null: [" + namedValueInfo.name + "]");
            } else {
            	// 具体解析参数,是模板方法,在子类实现
                Object arg = this.resolveName(resolvedName.toString(), nestedParameter, webRequest);
                if (arg == null) {
                    if (namedValueInfo.defaultValue != null) {
                        arg = this.resolveStringValue(namedValueInfo.defaultValue);
                    } else if (namedValueInfo.required && !nestedParameter.isOptional()) {
                        this.handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
                    }
    
                    arg = this.handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
                } else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
                    arg = this.resolveStringValue(namedValueInfo.defaultValue);
                }
    			// 如果不为空,则用它创建binder并转换解析出的参数
                if (binderFactory != null) {
                    WebDataBinder binder = binderFactory.createBinder(webRequest, (Object)null, namedValueInfo.name);
    
                    try {
                        arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
                    } catch (ConversionNotSupportedException var11) {
                        throw new MethodArgumentConversionNotSupportedException(arg, var11.getRequiredType(), namedValueInfo.name, parameter, var11.getCause());
                    } catch (TypeMismatchException var12) {
                        throw new MethodArgumentTypeMismatchException(arg, var12.getRequiredType(), namedValueInfo.name, parameter, var12.getCause());
                    }
                }
    			// 对解析出的参数进行后置处理
                this.handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
                return arg;
            }
        }
    

    首先根据参数类型会去到NamevalueInfo,然后将它传入模板方法resolveName由子类具体实现,最后对解析的结果处理,内部类NamevalueInfo

     protected static class NamedValueInfo {
     		// 参数名
            private final String name;
            // 是否必须
            private final boolean required;
            @Nullable
            // 默认值
            private final String defaultValue;
    
            public NamedValueInfo(String name, boolean required, @Nullable String defaultValue) {
                this.name = name;
                this.required = required;
                this.defaultValue = defaultValue;
            }
        }
    

    PathVariableMethodArgumentResolver类

    public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver implements UriComponentsContributor {
        private static final TypeDescriptor STRING_TYPE_DEscriptOR = TypeDescriptor.valueOf(String.class);
    
        public PathVariableMethodArgumentResolver() {
        }
    
        public boolean supportsParameter(MethodParameter parameter) {
            if (!parameter.hasParameterAnnotation(PathVariable.class)) {
                return false;
            } else if (!Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
                return true;
            } else {
                PathVariable pathVariable = (PathVariable)parameter.getParameterAnnotation(PathVariable.class);
                return pathVariable != null && StringUtils.hasText(pathVariable.value());
            }
        }
    
        protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
            PathVariable ann = (PathVariable)parameter.getParameterAnnotation(PathVariable.class);
            Assert.state(ann != null, "No PathVariable annotation");
            return new PathVariableMethodArgumentResolver.PathVariableNamedValueInfo(ann);
        }
    
    	// // 具体解析
        @Nullable
        protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
            Map uriTemplateVars = (Map)request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, 0);
            return uriTemplateVars != null ? uriTemplateVars.get(name) : null;
        }
    
    
        protected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException {
            throw new MissingPathVariableException(name, parameter);
        }
    
        protected void handleResolvedValue(@Nullable Object arg, String name, MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest request) {
            String key = View.PATH_VARIABLES;
            int scope = 0;
            Map pathVars = (Map)request.getAttribute(key, scope);
            if (pathVars == null) {
                pathVars = new HashMap();
                request.setAttribute(key, pathVars, scope);
            }
    		// 存储
            ((Map)pathVars).put(name, arg);
        }
    
        public void contributeMethodArgument(MethodParameter parameter, Object value, UriComponentsBuilder builder, Map uriVariables, ConversionService conversionService) {
            if (!Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
                PathVariable ann = (PathVariable)parameter.getParameterAnnotation(PathVariable.class);
                String name = ann != null && StringUtils.hasLength(ann.value()) ? ann.value() : parameter.getParameterName();
                String formatted = this.formatUriValue(conversionService, new TypeDescriptor(parameter.nestedIfOptional()), value);
                // 存储
                uriVariables.put(name, formatted);
            }
        }
    
    	// 格式化
        @Nullable
        protected String formatUriValue(@Nullable ConversionService cs, @Nullable TypeDescriptor sourceType, Object value) {
            if (value instanceof String) {
                return (String)value;
            } else {
                return cs != null ? (String)cs.convert(value, sourceType, STRING_TYPE_DEscriptOR) : value.toString();
            }
        }
    
        private static class PathVariableNamedValueInfo extends NamedValueInfo {
            public PathVariableNamedValueInfo(PathVariable annotation) {
                super(annotation.name(), annotation.required(), "nttnttnue000ue001ue002nttttn");
            }
        }
    }
    
    
    
    

    涉及方法

    • getNamevalueInfo:通过参数类型获得NamedValueInfo,PathVariableNamedValueInfo 根据构造方法使用@PAthVariable注解的value创建了PathVariableNamedValueInfo
    • resolveName:具体解析参数,模板方法,可以看出PathVariableMethodArgumentResolver 实现直接从request中获取的HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE属性的值,这个是是在RequestMappingInfoHandlerMapping中的handlerMathch中设置的,也就是在HandlerMapping中根据loouupPath找到处理请求的处理器之后设置的
    • resolveDefaultValue:设置默认值
    • handlerMissingValue:参数必须存在并且没有默认值,就会调用该模板方法
    • handlerResolverValue:处理解析出的参数值的模板方法,PathVariableMethodArgumentResolver 实现将解析的参数设置到request中
    2.6HandlerMethodReturnValueHandler

    作用在ServletInvocableHandlerMethod中,作用是处理处理器执行后的返回值,主要由三个功能

    • 将对应的参数添加到Model
    • 设置view
    • 如果请求已经处理完成ModelAndViewContainer的requestHandled为true

    原理和上述类似,主要一个包括判断支持、一个用于具体处理返回值,有很多实现子类

    3、总结
    • HandlerAdapter主要的四个实现类,RequestMappingHandlerAdapter较为复杂,其他简单,应该是SpringMVC最复杂的组件
    • 主要流程三步骤:将诶西参数、执行请求、处理返回值
    • 解析参数的过程参数来源有:Model、request,前者通过FlashMapManager和ModelFactory管理
    • 执行请求是HandlerMethod的子类ServletInvocableHandlerMethod,实际执行的时InvocableHandlerMethod
    • 返回值有HandlerMethodReturnValueHandler处理,不同的返回值对应不同的实现子类
    三、ViewResolver

    主要作用是根据视图名和Locale解析出视图,解析过程主要做两件事

    • 解析出使用的模板
    • 解析出视图的类型

    主要的实现类

    • ContentNegotiatingViewResolver主要作用是在别的解析器解析的结果加上Content-Type,对视图的解析并不是自己完成的,而是使用封装的ViewResolver来进行的,整个过程:首先遍历所封装的ViewResolver具体解析视图,可能会有多个结果,然后在使用request获取的Content-Type,最后对这两个结果进行匹配查找最优的视图
    • AbstractCachingViewResolver系列:提供了统一的缓存功能,当视图解析过一次就被缓存起来,直到缓存被删除前视图的解析都会从缓存中获取
    四、RequestToViewTranslator

    五、HandlerExceptionResolver

    主要作用是解析请求处理过程中产生的异常

    • AbstractHandlerExceptionResolver:模板类和子类ExceptionHandlerExceptionResolver一起完成@ExceptionHandler注解方法进行异常解析
    • DefaultHandlerExceptionResolver:按照不同类型分别对异常解析
    • ResponseStatusExceptionResolver:解析有@ResponseStatus注解类型的异常
    • SimpleMappingExceptionResolver:通过配置的异常和view的对应关系来解析异常

    解析过程主要包括:给ModelAndView设置相应内容、设置response的相关属性,当然可以有一些辅助功能如记录日志

    @Override
    	@Nullable
    	public ModelAndView resolveException(
    			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
    
    		// 判断当前ExceptionResolver是否可以解析所传入处理器所抛出的异常
    		if (shouldApplyTo(request, handler)) {
    			prepareResponse(ex, response);
    			// 模板方法
    			ModelAndView result = doResolveException(request, response, handler, ex);
    			if (result != null) {
    				// Print debug message when warn logger is not enabled.
    				if (logger.isDebugEnabled() && (this.warnLogger == null || !this.warnLogger.isWarnEnabled())) {
    					logger.debug("Resolved [" + ex + "]" + (result.isEmpty() ? "" : " to " + result));
    				}
    				// Explicitly configured warn logger in logException method.
    				logException(ex, request);
    			}
    			return result;
    		}
    		else {
    			return null;
    		}
    	}
    
    六、MultipartResolver

    用于处理上传请求,有两个实现类,

    • StandardServletMultipartResolver (使用Servlet3.0的标准上传格式)

    • CommonsMultipartResolver(后者使用Apache的commons-fileupload)

    1、StandardServletMultipartResolver

    配置的参数

    七、SpringMVC原理总结 1、原理总结

    2、跟踪一个处理流程

    SpringMVC的处理过程

    下面具体分析

    0、SpringMVC的创建

    1、发送请求(Servlet容器)

    2、ServletRequest转为HttpServletrequest(HttpSetvlet)

    3、请求初步经service()处理(frameworkServlet、HttpServlet之间)

    4、请求汇总到processRequest(frameworkServlet)

    5、doService调用doDispatch内部调用getHandler(DispatchServlet)

    6、根据请求寻找Handler及其处理方法(RequestMappingHandlerMapping)

    7、找到处理方法之后将请求参数的设置request里面(RequestMappingInfoHandlerMapping)

    8、根据Handler找HandlerAdapter之后处理请求(DispatchServlet)

    9、HandlerAdapter调用Handler处理请求(RequestMappingHandlerAdapter)
    • HandlerAdapter的handler()方法是模板方法,进而调用子类RequestMappingHandlerAdapter的getHandlerInternal()方法

    10、执行请求对应方法之前(RequestMappingHandlerAdapter)

    11、类似切面的方法初始化Model数据(ModelFactory)

    12、执行请求对应方法(InvocableHandlerMethod、处理器FollowMeController)

    13、视图View的处理(ServletInvocableHandlerMethod、ViewNameMethodReturnValueHandler)

    14、ModelAndView的处理(RequestMappingHandlerAdapter)

    15、准备View的检查及其后续拦截器(DispatchServlet)

    16、准备View的渲染(DispatchServlet)

    17、请求处理完成(RedirectView、DispatchServlet、frameworkServlet)

    转载请注明:文章转载自 www.mshxw.com
    我们一直用心在做
    关于我们 文章归档 网站地图 联系我们

    版权所有 (c)2021-2022 MSHXW.COM

    ICP备案号:晋ICP备2021003244-6号