交流
商城
MCN
登入
注册
首页
提问
分享
讨论
建议
公告
动态
发表新帖
发表新帖
springmvc第4 章:HandlerAdapter
分享
未结
0
989
李延
LV6
2021-05-25
悬赏:20积分
# HandlerAdapter 在这里我们主要以RequestMappingHandlerAdapter为示例说明。 HandlerAdapter是mvc中最复制的组件,整个组件处理事情主要包括: - 参数绑定 - 使用处理器处理请求 - 封装返回值 其中参数绑定最为复杂,我们都知道我们使用的处理器可以是任何方法。对于参数类型和数量都是不确定的,所以难度非常大。 # 初始化 我们看一下它的初始化方法afterPropertiesSet ```java @Override public void afterPropertiesSet() { // Do this first, it may add ResponseBody advice beans //处理ControllerAdvice注解 initControllerAdviceCache(); //初始化argumentResolvers if (this.argumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers(); this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } //初始化initBinderArgumentResolvers if (this.initBinderArgumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers(); this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } //初始化returnValueHandlers if (this.returnValueHandlers == null) { List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(); this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); } } ``` 对于上面的3个变量,大致说明: - argumentResolvers: 方法的参数解析器 - initBinderArgumentResolvers:@InitBinder 参数解析器 - returnValueHandlers:用于返回值处理成ModelAndView 其具体的初始化内容,我们在其章节说明。 ## initControllerAdviceCache ```java private void initControllerAdviceCache() { if (getApplicationContext() == null) { return; } //筛选出所有有ControllerAdvice注解的方法 List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); List<Object> requestResponseBodyAdviceBeans = new ArrayList<>(); for (ControllerAdviceBean adviceBean : adviceBeans) { Class<?> beanType = adviceBean.getBeanType(); if (beanType == null) { throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean); } //找到有RequestMapping和ModelAttribute的方法。缓存到modelAttributeAdviceCache中 Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS); if (!attrMethods.isEmpty()) { this.modelAttributeAdviceCache.put(adviceBean, attrMethods); } //找到有InitBinder注解的方法,缓存到initBinderAdviceCache中 Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS); if (!binderMethods.isEmpty()) { this.initBinderAdviceCache.put(adviceBean, binderMethods); } // 对于RequestBodyAdvice和ResponseBodyAdvice 子类 requestResponseBodyAdvice if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) { requestResponseBodyAdviceBeans.add(adviceBean); } } if (!requestResponseBodyAdviceBeans.isEmpty()) { this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans); } if (logger.isDebugEnabled()) { int modelSize = this.modelAttributeAdviceCache.size(); int binderSize = this.initBinderAdviceCache.size(); int reqCount = getBodyAdviceCount(RequestBodyAdvice.class); int resCount = getBodyAdviceCount(ResponseBodyAdvice.class); if (modelSize == 0 && binderSize == 0 && reqCount == 0 && resCount == 0) { logger.debug("ControllerAdvice beans: none"); } else { logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize + " @InitBinder, " + reqCount + " RequestBodyAdvice, " + resCount + " ResponseBodyAdvice"); } } } ``` 我们看到在这里处理了和ControllerAdvice注解相关的内容。我们在demo章节,用示例,说明它们的用处。 # 主要方法 这里我们主要分析前面使用过的supports和handle方法。 ## supports 判断是否支持当前的Handler ```java @Override public final boolean supports(Object handler) { return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler)); } ``` 在父类实现,一方面判断是否为HandlerMethod子类。另一方面调用子类的supportsInternal方法判断,而在这个类中: ```java @Override protected boolean supportsInternal(HandlerMethod handlerMethod) { return true; } ``` 所以对于所有handler是HandlerMethod的都会交给这个类处理 ## handle ```java @Override @Nullable public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler); } ``` 我们直接看handleInternal方法: ```java @Override protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav; checkRequest(request); // 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 = (request, response, handlerMethod); } if (!response.containsHeader(HEADER_CACHE_CONTROL)) { if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers); } else { prepareResponse(response); } } return mav; } ``` 继续看invokeHandlerMethod方法: ```java @Nullable protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { //将request封装为ServletWebRequest对象 ServletWebRequest webRequest = new ServletWebRequest(request, response); try { //创建binderFactory WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); //创建ModelFactory ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); //创建ServletInvocableHandlerMethod对象,这个就是执行请求的对象 ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); //为invocableMethod 设置一系列属性 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); } //调用invokeAndHandle 就是在这一步调用了我们的方法 invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } } ``` 在上面的代码中我们发现有很多的组件。我们逐一分析一下: - WebDataBinderFactory :WebDataBinder对象的工厂类,而WebDataBinder用于参数绑定,我们平常使用的InitBinder注解就是这个对象处理的。 - ModelFactory : Model工厂类,同于初始化Model - ServletInvocableHandlerMethod :Servlet 方法处理器,所以的参数绑定、方法调用、返回值处理都在这个类中。 - ModelAndViewContainer:HandlerAdapter在处理请求时上下文数据的传递工作是由ModelAndViewContainer负责的. 我们具体分析每个组件初始化过程。 ### getDataBinderFactory ```java private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception { Class<?> handlerType = handlerMethod.getBeanType(); //加载缓存 Set<Method> methods = this.initBinderCache.get(handlerType); if (methods == null) { methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS); this.initBinderCache.put(handlerType, methods); } List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>(); // 首先加载本类中的InitBinder注解方法 this.initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) -> { if (controllerAdviceBean.isApplicableToBeanType(handlerType)) { Object bean = controllerAdviceBean.resolveBean(); for (Method method : methodSet) { initBinderMethods.add(createInitBinderMethod(bean, method)); } } }); //将全局的InitBinder注解方法也合并进来,这个在初始化的时候加载的。 for (Method method : methods) { Object bean = handlerMethod.getBean(); initBinderMethods.add(createInitBinderMethod(bean, method)); } //最后创建出ServletRequestDataBinderFactory对象 return createDataBinderFactory(initBinderMethods); } ``` 我们看到在创建ServletRequestDataBinderFactory对象的时候将InitBinder注解的方法传给了它,其中分为两部分: 1. 一部分为全局的InitBinder。这部分通过ControllerAdvice注解的类加载进来。 2. 另一部分是当前类里面的InitBinder。 对于ServletRequestDataBinderFactory具体的使用我们在调用的时候进行说明 ### getModelFactory ```java private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) { SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod); Class<?> handlerType = handlerMethod.getBeanType(); Set<Method> methods = this.modelAttributeCache.get(handlerType); if (methods == null) { methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS); this.modelAttributeCache.put(handlerType, methods); } List<InvocableHandlerMethod> attrMethods = new ArrayList<>(); // Global methods first this.modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> { if (controllerAdviceBean.isApplicableToBeanType(handlerType)) { Object bean = controllerAdviceBean.resolveBean(); for (Method method : methodSet) { attrMethods.add(createModelAttributeMethod(binderFactory, bean, method)); } } }); for (Method method : methods) { Object bean = handlerMethod.getBean(); attrMethods.add(createModelAttributeMethod(binderFactory, bean, method)); } return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler); } ``` 这部分基本上与之前一致,将包含ModelAttribute注解的类加载进来,也是分为全局与当前类两部分。 ### ServletInvocableHandlerMethod初始化 这里我们看到之前准备的所有组件都传给了这个类,并且调用了invokeAndHandle方法。 我们请求的之后的逻辑都在这个类中,我们在下面的文章我详细说明。
回帖
消灭零回复
提交回复
热议榜
java 相关知识分享
8
好的程序员与不好的程序员
6
写给工程师的十条精进原则
5
spring boot以jar包运行配置的logback日志文件没生成
5
一步一步分析SpringBoot启动源码(一)
5
MockMvc测试
5
【吐槽向】是不是有个吐槽的板块比较好玩
4
logstash jdbc同步mysql多表数据到elasticsearch
3
IntelliJ IDEA 优质License Server
3
.gitignore忽略规则
3
SpringBoot启动源码分析
3
一步一步分析SpringBoot启动源码(三)
3
2
一步一步分析SpringBoot启动源码(二)
2
积分不够将无法发表新帖
2
官方产品
Meta-Boot - 基于MCN
MCN - 快速构建SpringBoot应用
微信扫码关注公众号