美文网首页
HandlerAdapter

HandlerAdapter

作者: lazyguy | 来源:发表于2017-10-18 09:56 被阅读0次

    HandlerAdapter

    直译就是Handler的适配器,主要的作用就是真正去执行Handler里面包含的的逻辑,
    其中3个方法:

    boolean supports(Object handler);    该是适配器是否适用于传入的Handler
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler);执行handler的逻辑,返回其对应的ModelAndView
    long getLastModified(HttpServletRequest request, Object handler); 包装方法,返回lastModified时间
    

    AbstractHandlerMethodAdapter

    1. 这个类实现了HandlerAdapter:其中supports方法初步判断传进来的Handler是否是HandlerMethod,然后其余的逻辑交给子类的钩子方法。
    2. 实现了Ordered接口:因为AbstractHandlerMethodAdapter可能在spring上下文中有多个。
    3. 继承了WebContentGenerator类:????

    RequestMappingHandlerAdapter

    这个Adapter是HandlerAdapter组件真正干大事的那个类。
    此类的代码分为2部分。

    1. 从InitializingBean接口继承的afterPropertiesSet方法完成一些初始化工作。
    2. handlerInternal作为父类的handle方法被调用时,真正干活的那个方法。
    先说第一部分,初始化的工作:afterPropertiesSet方法,来自于InitializingBean接口,会在此类被初始化为Bean后执行。
    @Override
        public void afterPropertiesSet() {
            //initControllerAdviceCache。如其名字暗示的一样,此方法的主要作用是在初始化@ControllerAdvice相关的配置
            // Do this first, it may add ResponseBody advice beans
            initControllerAdviceCache();
            if (this.argumentResolvers == null) {
                List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
                this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
            }
            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);
            }
        } 
    
    1. initControllerAdviceCache。如其名字暗示的一样,此方法的主要作用是在初始化@ControllerAdvice相关的配置
    private void initControllerAdviceCache() {
            //先拿到ApplicationContext
            if (getApplicationContext() == null) {
                return;
            }
            //info记录是在哪个ApplicationContext中找@ControllerAdvice的
            if (logger.isInfoEnabled()) {
                logger.info("Looking for @ControllerAdvice: " + getApplicationContext());
            }
            //从上下文中取出所有被@ControllerAdvice标记的bean,封装为ControllerAdviceBean的List。
            //这里使用的是ControllerAdviceBean的一个构造器方法,通过传入ApplicationContext,去遍历上下文中的所有带有@ControllerAdvice注解的bean
            //ControllerAdviceBean保存了被注解的类的一些原始信息,比如@ControllerAdvice的扫描范围,是否有@Order排序注解等等
            List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
            
            //将取出的ControllerAdviceBean按Order信息排序一遍
            AnnotationAwareOrderComparator.sort(beans);
    
            List<Object> requestResponseBodyAdviceBeans = new ArrayList<Object>();
            //遍历取出来的ControllerAdviceBean,做了3件事
            for (ControllerAdviceBean bean : beans) {
            //第一件事是找出其中的@ModelAtrribute标记的方法,放入成员变量modelAttributeAdviceCache
                Set<Method> attrMethods = MethodIntrospector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
                if (!attrMethods.isEmpty()) {
                    this.modelAttributeAdviceCache.put(bean, attrMethods);
                    if (logger.isInfoEnabled()) {
                        logger.info("Detected @ModelAttribute methods in " + bean);
                    }
                }
            //第二件事是找出其中的@InitBinder标记的方法,放入成员变量initBinderAdviceCache
                Set<Method> binderMethods = MethodIntrospector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
                if (!binderMethods.isEmpty()) {
                    this.initBinderAdviceCache.put(bean, binderMethods);
                    if (logger.isInfoEnabled()) {
                        logger.info("Detected @InitBinder methods in " + bean);
                    }
                }
            //第三件事是判断这些ControllerAdviceBean是否是RequestBodyAdvice||ResponseBodyAdvice的子类,放入成员变量requestResponseBodyAdvice
                if (RequestBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
                    requestResponseBodyAdviceBeans.add(bean);
                    if (logger.isInfoEnabled()) {
                        logger.info("Detected RequestBodyAdvice bean in " + bean);
                    }
                }
                if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
                    requestResponseBodyAdviceBeans.add(bean);
                    if (logger.isInfoEnabled()) {
                        logger.info("Detected ResponseBodyAdvice bean in " + bean);
                    }
                }
            }
    
            if (!requestResponseBodyAdviceBeans.isEmpty()) {
                this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
            }
        
    

    所以initControllerAdviceCache这个方法里初始化了3个成员变量

    1. modelAttributeAdviceCache : 保存ControllerAdvice中的ModelAttribute方法
    2. initBinderAdviceCache:保存ControllerAdvice中的initBinder方法
    3. requestResponseBodyAdvice: 保存ControllerAdvice中继承于RequestBodyAdvice||ResponseBodyAdvice的方法

    这就是initControllerAdvice方法的全部逻辑。

    接着回到afterPropertiesSet方法中。基础初始化了3个成员变量

    argumentResolvers,initBinderArgumentResolvers,returnValueHandlers

    这3个成员变量没有被初始化的话,赋予默认值

    argumentResolvers:用于给处理器方法和注释了@ModelAttribute的方法设置参数。

    initBinderArgumentResolvers:用于给注释了@initBinder的方法设置参数。

    returnValueHandlers:用于将处理器的返回值处理成ModelAndView的类型。

    所以在afterPropertiesSet方法中总共初始化了6个成员变量待用。

    第二部分,被调用的时候的handleInternal方法,来自于父类的模板方法
    @Override
        protected ModelAndView handleInternal(HttpServletRequest request,
                HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
            ModelAndView mav;
           //检查我们当前Adapter是否支持此request(方法和session),否则抛出异常
            checkRequest(request);
           //(同步或者不锁定)调用invokeHandlerMethod,得到ModelAndView这结果
            // 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;
        }
    
    

    其中的invokeHandlerMethod方法

    protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
                HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
            //将传入的request,response封装为ServletWebRequest
            ServletWebRequest webRequest = new ServletWebRequest(request, response);
            try {
                //创建WebDataBinderFactory,里面包含了initBinderAdviceCache和handlerMethod自己包含的initBinder
                WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
               //还是同样的套路创建包含了ModelAttribute方法的ModelFactory      
                ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
                //通过HandlerMethod创建包装类ServletInvocableHandlerMethod,塞入相关的成员变量待用
                ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
                invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
                invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
                invocableMethod.setDataBinderFactory(binderFactory);
                invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
                //创建ModelAndViewContainer
                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);
            }
            finally {
                webRequest.requestCompleted();
            }
        }
    

    1.1 第一步
    1.2 第二步,将HandlerMethod和WebBinderFactory创建ModelFactory
    ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

    private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
              //通过handlerMethod创建相应的SessionAttributesHandler,阅读getSessionAttributesHandler里面的代码可以知道,
    //主要是查找HandlerType上是否有@SessionAttribute的注解,创建对应的SessionAttributesHandler,
    //并将创建的SessionAttributesHandler放入属性变量sessionAttributesHandlerCache。
    //SessionAttributesHandler主要是封装handlerMethod带来的相关Session信息,
    //SessionAttributeStore是SessionAttributesHandler用来存放session信息的地方,从代码可以看出,其实就是放入Request对应的session。为啥这样绕呢?大概是为了解耦可以放到其他地方。
            SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
    //第二步将modelAttributeAdviceCache中存放的ModelAttribute的方法(从@ControllerAdvice中提取出来的) 。
    //创建InvocableHandlerMethod,里面包含了WebDataBinderFactory,HandlerMethod,ModelAttribute的方法,
    //和成员变量argumentResolvers,parameterNameDiscoverer
            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<InvocableHandlerMethod>();
            // Global methods first
            for (Entry<ControllerAdviceBean, Set<Method>> entry : this.modelAttributeAdviceCache.entrySet()) {
                if (entry.getKey().isApplicableToBeanType(handlerType)) {
                    Object bean = entry.getKey().resolveBean();
                    for (Method method : entry.getValue()) {
                        attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
                    }
                }
            }
    //第三步将此HandlerMethod上私有的ModelAttribute的方法同理创建InvocableHandlerMethod,合并放入attrMethods
            for (Method method : methods) {
                Object bean = handlerMethod.getBean();
                attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
            } 
    //第四步 创建ModelFactory,包含以下3种组件
    //ModelAttribute的方法list,
    //WebDataBinderFactory,
    //SessionAttributesHandler(HandlerMethod上@SessionAttribute的想关信息)
            return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
        }
    

    1.3 第三步 创建ModelAndViewContainer

    ModelAndViewContainer mavContainer = new ModelAndViewContainer();
    //把request里面的INPUT_FLASH_MAP_ATTRIBUTE属性取出来放入
    mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
    //将HandlMethod中相关的ModelAttribute和SessionAttribute的属性提前设置与mavContainer里面的Model中
    modelFactory.initModel(webRequest, mavContainer, invocableMethod);
    //设置在Request重定向的时候是否使用DefaulModel
    mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
    

    1.4 第四步 异步处理
    1.5 第五步 真正调用HandlerMethod的方法
    invocableMethod.invokeAndHandle(webRequest, mavContainer);

    ModelAndViewContainer

    其中并没有太过复杂的逻辑,如名字暗示的一样,它主要是作为一些属性的容器而存在的,那到底有些什么属性呢?

        private boolean ignoreDefaultModelOnRedirect = false;
        //视图,可以是任何类型
        private Object view;
        //存储想输入页面的属性,本质是LinkedHashMap的一种扩展
        private final ModelMap defaultModel = new BindingAwareModelMap();
        //redirect????    
        private ModelMap redirectModel;
        //????
        private boolean redirectModelScenario = false;
    
        /* Names of attributes with binding disabled */
        private final Set<String> bindingDisabledAttributes = new HashSet<String>(4);
    
        private HttpStatus status;
    
        private final SessionStatus sessionStatus = new SimpleSessionStatus();
    
        private boolean requestHandled = false;
    

    相关文章

      网友评论

          本文标题:HandlerAdapter

          本文链接:https://www.haomeiwen.com/subject/wtutjxtx.html