SpringMVC的一些扩展点解读

Spring扩展点

1、springMVC扩展

1.1、SpirngMVC–请求映射扩展

直接继承自RequestMappingHandlerMapping即可,整个mvc最重要的两个类中的一个
作用就是生成路径到类到方法的映射容器,另一个是RequestMappingHandlerAdapter,就是请求调用过程的配对。

1.2、SpirngMVC–拦截器

Interceptor接口

HandlerInterceptor

public interface HandlerInterceptor {
    
    
    //请求预处理,如登入校验
    //返回值:true表示继续流程,false直接respnse
    boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception;
    //后处理,方法调用之后处理方法
    void postHandle(
            HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception;
   //请求完成时处理,如释放资源
    void afterCompletion(
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception;
}
1.3、SpirngMVC–方法处理适配器

HandlerAdapter
在这里插入图片描述

public interface HandlerAdapter {
    
    
    //判断是否支持传入的handler
    boolean supports(Object handler);
    //使用handler处理请求返回modelAndView
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
    //获取资源的LastModified值,配合If-Modified-Since做缓存更新操作
    long getLastModified(HttpServletRequest request, Object handler);
}

请看接口继承结构图共有6个实现类如下:

  • AbstractHandlerMethodAdapter
  • SimpleControllerHandlerAdapter
  • SimpleServletHandlerAdapter
  • HttpRequestHandlerAdapter
  • CompositeHandlerAdapter
  • EndpointWebMvcChildContextConfiguration.CompositeHandlerAdapter静态内部类

代码并不复杂,就是做了一层适配实现。不多介绍

我们来看看RequestMappingHandlerAdapter这个的具体实现,它继承自AbstractHandlerMethodAdapter,后者就是对适配器做了一层适配,封装了三个模板方法提供给前者实现。

我们先看它的初始化

@Override
	public void afterPropertiesSet() {
    
    
		// 此处初始化缓存了controller层的一些增强熟悉,如ControllerAdvice,ModelAttribute、InitBinder、RequestBodyAdvice、ResponseBodyAdvice
		initControllerAdviceCache();
		//添加参数解析器即被处理的方法参数解析校验然后塞给方法
		if (this.argumentResolvers == null) {
    
    
			List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
			this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
        //@InitBinder注解参数解析器
		if (this.initBinderArgumentResolvers == null) {
    
    
			List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
			this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
        //返回值处理器
		if (this.returnValueHandlers == null) {
    
    
			List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
			this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
		}
	}

其主要入口为handleInternal真正执行调用的过程是invokeHandlerMethod

protected ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
    

		ModelAndView mav;
		checkRequest(request);

		//由于session非线程安全,所以这边新增一个判断,理论上这种情况几乎不可能发生,所以这里默认为false。
		if (this.synchronizeOnSession) {
    
    
			HttpSession session = request.getSession(false);
            //判单session是否存在判断是否需要添加互斥锁mutex
			if (session != null) {
    
    
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
    
    
					mav = invokeHandlerMethod(request, response, handlerMethod);
				}
			}
			else {
    
    
				//不存在session不需要添加互斥锁直接调用
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
    
    
			//不考虑session同步安全性直接调用
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}
		//判断响应头是否包含缓存控制
		if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
    
    
			if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
    
    
                //申请相应秒数的缓存,即第二个参数,默认为0所以你如果缓存控制,还要设置这个时间才有用
				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
			}
			else {
    
    
                //直接设置响应参数
				prepareResponse(response);
			}
		}

		return mav;
	}
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);
			if (this.argumentResolvers != null) {
    
    
				invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			}
			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);
			}
			//前面都是准备工作,真正发起调用在这一行ServletInvocableHandlerMethod由这个对象发起调用,调用完成之后调用前面设置的返回处理类进行处理,如如果注解的是@ResponseBody,怎么处理等等。HandlerMethodReturnValueHandlerComposite返回值处理组合类
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
    
    
				return null;
			}

			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
    
    
			webRequest.requestCompleted();
		}
	}

内容太多不一一展开了,看代码养成一个习惯就好,从顶层接口一层层往下走,结合idea工具的类图进行全局预览效果更佳。

1.4、SpirngMVC–参数解析器

HandlerMethodArgumentResolver – 处理方法参数解析器

如果你想定义自己的参数解析方式,可以实现此接口,此接口就两个方法

public interface HandlerMethodArgumentResolver {
    
    
    //判断是否支持解析的类型
    boolean supportsParameter(MethodParameter var1);

    @Nullable
    //如何解析
    Object resolveArgument(MethodParameter var1, @Nullable ModelAndViewContainer var2, NativeWebRequest var3, @Nullable WebDataBinderFactory var4) throws Exception;
}

参加InvocableHandlerMethod.getMethodArgumentValues层层回跟即可

1.5、SpirngMVC–类型转换器

Converter – 类型转换器

@FunctionalInterface
public interface Converter<S, T> {
    
    

	//如何转换
	@Nullable
	T convert(S source);

}
1.6、SpirngMVC–视图解析器

ViewResolver 视图解析器,有没有很熟悉的面试题的感觉没错这个就是面试经常问到的前端到后台调用的整个过程中的视图解析器
具体流程请看DispatcherServlet.render层层回跟即可

1.7、SpringMVC–异常解析器

HandlerExceptionResolver接口
具体流程参看DispatcherServlet.processHandlerException层层回跟即可

猜你喜欢

转载自blog.csdn.net/a807719447/article/details/114843795