美文网首页
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