2023-09-14  阅读(43)
原文作者:王伟王胖胖 原文地址: https://blog.csdn.net/wangwei19871103/article/details/105531403

处理大致流程图

202309142301344611.png

获取处理器适配器

适配器模式

为什么要处理器适配器,我们前面不是获取处理器方法了么,直接调用就好啦。对没错,但是那可能只是一种处理器的方式,也就是HandlerMethod,以前还有另外的方式哦,比如实现Controller接口的:

202309142301360432.png
还有实现HttpRequestHandler接口的:

202309142301375243.png
他们的接口都不一样,总得兼容吧,处理接口不一致的办法不就是适配器模式嘛,你接口不同,我用不同的适配器来适配,对外都是统一接口,如果以后有新的实现,我只要添加适配器即可,这里就是适配器模式的应用啦。

DispatcherServlet的getHandlerAdapter

这里就是遍历所有的处理器适配器,看哪个是适配的就直接返回了。

    	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    		if (this.handlerAdapters != null) {
    			for (HandlerAdapter adapter : this.handlerAdapters) {
    				if (adapter.supports(handler)) {
    					return adapter;
    				}
    			}
    		}
    		throw new ServletException("No adapter for handler [" + handler +
    				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    	}

如何适配

RequestMappingHandlerAdapter的supports

判断是否是HandlerMethod类型的。

    	@Override
    	public final boolean supports(Object handler) {
    		return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
    	}
    	@Override
    	protected boolean supportsInternal(HandlerMethod handlerMethod) {
    		return true;
    	}

HttpRequestHandlerAdapter的supports

是不是实现了HttpRequestHandler接口。

    	@Override
    	public boolean supports(Object handler) {
    		return (handler instanceof HttpRequestHandler);
    	}

SimpleControllerHandlerAdapter的supports

是不是实现了Controller接口。

    	@Override
    	public boolean supports(Object handler) {
    		return (handler instanceof Controller);
    	}

至于这些是什么时候初始化的,我就不说了,前面已经把方法都演示过了,就是一些自动配置类里,自己可以去找啦,剩下的适配器自己可以也去看看。

处理器适配器处理

其实前面有拦截器,后面会说,还是说主要的,处理器适配器获得到之后,要进行适配器调用啦,不同的适配器调用方式不一样,但是核心还是调用处理器的方法啦:

    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

HttpRequestHandlerAdapter的handle

转换成接口类型,调用接口。

    	@Override
    	@Nullable
    	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    
    		((HttpRequestHandler) handler).handleRequest(request, response);
    		return null;
    	}

SimpleControllerHandlerAdapter的handle

这个也一样。

    	@Override
    	@Nullable
    	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    
    		return ((Controller) handler).handleRequest(request, response);
    	}

AbstractHandlerMethodAdapter的handle

这个是重点,我们要详细说。

    	@Override
    	@Nullable
    	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    
    		return handleInternal(request, response, (HandlerMethod) handler);
    	}

RequestMappingHandlerAdapter的handleInternal

留出核心代码,就是处理器处理,然后准备response

    @Override
    	protected ModelAndView handleInternal(HttpServletRequest request,
    			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
    		ModelAndView mav;
    		...
    		mav = invokeHandlerMethod(request, response, handlerMethod);//		
    		...
    		prepareResponse(response);
    		...
    		return mav;
    	}

invokeHandlerMethod

这里面的才是重点,每个都挺复杂的,没关系,我们一个个来看,新不追求太细节的东西,知道大致流程,大致的流程就是创建数据绑定工厂,这个东西就是做参数绑定用的,后面会介绍,然后是模型工厂,最终是要创建模型返回的,所以需要这个,而且数据绑定工厂也会封装在里面。然后初始化模型,会根据方法的参数来找解析器解析,找到的话就可以解析出参数,最后封装到模型里去,最后再调用处理器的方法处理,然后获取模型和视图返回。看起来好像没多少东西,其实里面还是表深的。

    @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);//模型工厂
    			//进行handlerMethod封装
    			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);//参数名探测器
    			//创建ModelAndView容器
    			ModelAndViewContainer mavContainer = new ModelAndViewContainer();
    			mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));//获取前面重定向来的属性
    			modelFactory.initModel(webRequest, mavContainer, invocableMethod);//初始化模型
    			mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
    
    			...
    			//调用处理方法
    			invocableMethod.invokeAndHandle(webRequest, mavContainer);
    			...
    
    			return getModelAndView(mavContainer, modelFactory, webRequest);
    		}
    		finally {
    			webRequest.requestCompleted();
    		}

下一篇来一个个讲吧。

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文