SpringMVC4-组件(二)-HandlerAdapter-1

《看透springMvc源代码分析与实践》学习笔记
SpringMVC 版本 4.1.5.RELEASE

HandlerAdapter的作用是具体使用HandlerMapping来干活的。
它在 DispatcherServlet.initHandlerAdapters(context)中被初始化,在DispatcherServlet.properties中配置,默认使用:HttpRequestHandlerAdapter, SimpleControllerHandlerAdapter, AnnotationMethodHandlerAdapter.

HandlerAdapter接口定义了三个方法:

  • supports : 判断是否支持掺入的Handler
  • handle : 使用Handle处理请求
  • getLastModified: 获取资源LastModified的值

HandlerAdapter 类图

在这里插入图片描述

HandlerAdapter的结构比较简单,一共有5类Adapter,其中只有RequestMappingHandlerAdapter有两层结构,其他的只有一层,都是直接实现的HandlerAdapter接口。

HttpRequestHandlerAdapter , SimpleServletHandlerAdapter, SimpleControllerHandlerAdapter
HttpRequestHandlerAdapter , SimpleServletHandlerAdapter, SimpleControllerHandlerAdapter 分别适配 HttpRequestHandler,Servlet,Controller类型的Handler,
方法非常简单,都是调用 handle里固定的代码,代码如下:

//org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
public class HttpRequestHandlerAdapter implements HandlerAdapter {
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		((HttpRequestHandler) handler).handleRequest(request, response);
		return null;
	}
}

//org.springframework.web.servlet.handler.SimpleServletHandlerAdapter
public class SimpleServletHandlerAdapter implements HandlerAdapter {
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		((Servlet) handler).service(request, response);
		return null;
	}
}

//org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		return ((Controller) handler).handleRequest(request, response);
	}

}

只有SimpleControllerHandlerAdapter 返回结果不是null.

AnnotationMethodHandlerAdapter
AnnotationMethodHandlerAdapter已经废弃。

@deprecated in Spring 3.2 in favor of
@link org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter RequestMappingHandlerAdapter}

这里不再详细分析。



RequestMappingHandlerAdapter 概述

分析 AbstractHandlerMethodAdapter

RequestMappingHandlerAdapter 继承自 AbstractHandlerMethodAdapter,AbstractHandlerMethodAdapter比较简单,代码如下:

public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
    //提供setter,配置时可设置顺序。
	private int order = Ordered.LOWEST_PRECEDENCE;

	public AbstractHandlerMethodAdapter() {
	    //是否限制仅支持: GET, HEAD and POST 
		super(false);
	}

	@Override
	public final boolean supports(Object handler) {
	    /**
	     * a. 必须为 HandlerMethod类型
	     * b. 还需满足supportsInternal的条件,supportsInternal为模板方法,由子类实现。 子类直接返回true.
	     *  ==== 综上 handler只需为HandlerMethod 即返回true.
	     */
		return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
	}
	
	@Override
	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		//调用handleInternal模板方法,由子类实现
		return handleInternal(request, response, (HandlerMethod) handler);
	}

	@Override
	public final long getLastModified(HttpServletRequest request, Object handler) {
	    //getLastModifiedInternal 模板方法 由子类实现 , 子类实现 直接返回 -1
		return getLastModifiedInternal(request, (HandlerMethod) handler);
	}
}

handleInternal

通过分析AbstractHandlerMethodAdapter可以发现,最终的处理逻辑全部交给了handleInternal方法,就是这个方法使用handler来处理请求.
handleInternal处理过程大概分为三个步骤:

  1. 准备好处理器所需的参数
  2. 使用处理器处理请求 ---- 直接利用反射调用处理器执行即可。
  3. 处理返回值,即将不同类型的返回值统一处理成ModelAndView类型。

参数绑定
这3步中,最复杂的是第1步即参数绑定,这一步需要根据hanlder的需要设置参数,参数类型、个数都不确定且此过程运用了大量的组件,给这部分代码带来了很大的复杂度。
想要理解参数绑定需要明白如下三个问题:

  • 都有哪些参数需要
    • 根据处理请求Handler确定
    • 当前处理器对应注释了@ModelAttribute、@InitBinder
  • 参数的值的来源
    • request请求中参数 : url、post以及请求头header中
    • cookie中参数
    • session中参数
    • 设置到FlashMap中的参数: 这种弄参数主要用于redirect传递参数
    • @SessionAttributes传递的参数
    • 注释@ModelAttribute方法设置的参数
  • 具体进行绑定的方法: 具体的参数解析使用HandlerMethodArgumentResolver类型的组件来完成。@ModelAttribute、@InitBinder、@ControllerAdvice用法


RequestMappingHandlerAdapter 结构

RequestMappingHandlerAdapter自身结构并不复杂,只不过是使用了很多组件,增加了对代码分析的难度。

RequestMappingHandlerAdapter 初始化

RequestMappingHandlerAdapter 实现了 InitializingBean接口,它的初始化工作是在afterPropertiesSet()方法中完成的,它的主要工作内容是初始化如下一些属性:

//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean {
    //用于给处理器方法和带有@ModelAttribute的方法设置参数
    private HandlerMethodArgumentResolverComposite argumentResolvers;
    
    //用于给注释了@InitBinder的方法设置参数
    private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
    
    //@ControllerAdvice类中, 带有@InitBinder 注解的方法
    private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache = new LinkedHashMap<ControllerAdviceBean, Set<Method>>();
    
    //@ControllerAdvice类中, 带有@ModelAttribute且不带有@RequestMapping 注解的方法		
    private final Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache = new LinkedHashMap<ControllerAdviceBean, Set<Method>>();
    
    //带有@ControllerAdvice且实现了ResponseBodyAdvice接口的 类	
    private List<Object> responseBodyAdvice = new ArrayList<Object>();
    
    //用于将处理器返回值 处理成 ModelAndView
    private HandlerMethodReturnValueHandlerComposite returnValueHandlers;	
    @Override
    public void afterPropertiesSet() {
        //初始化 带有@ControllerAdvice类的相关属性
        initControllerAdviceCache();

        if (this.argumentResolvers == null) {
            // 注①, 获取默认的ArgumentResolvers ,然后设置到argumentResolvers中  
            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);
        }
    }
    
    private void initControllerAdviceCache() {
        //寻找带有@ControllerAdvice 的bean
        List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
        Collections.sort(beans, new OrderComparator()); //排序

        List<Object> responseBodyAdviceBeans = new ArrayList<Object>();

        for (ControllerAdviceBean bean : beans) {
            //寻找带有@ModelAttribute && 不带有 @RequestMapping 的方法
            Set<Method> attrMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
            if (!attrMethods.isEmpty()) {
                this.modelAttributeAdviceCache.put(bean, attrMethods);
            }
            
            //寻找带有@InitBinder 的方法
            Set<Method> binderMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
            if (!binderMethods.isEmpty()) {
                this.initBinderAdviceCache.put(bean, binderMethods);
            }
            
            //寻找implements ResponseBodyAdvice接口的类
            if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
                responseBodyAdviceBeans.add(bean);
            }
        }
        
        if (!responseBodyAdviceBeans.isEmpty()) {
            /*
             * 将匹配到的responseBodyAdviceBeans添加到List最前面。 
             * ResponseBodyAdvice可以通过@ControllerAdvice注解注册 ,也可以直接注册到 RequestMappingHandlerAdapter中,
             * list.addAll(0, list2); 目的是让@ControllerAdvice注解注册的优先级更高
             */
            this.responseBodyAdvice.addAll(0, responseBodyAdviceBeans);
        }
    }
		
}

上述过程中,argumentResolvers 、 initBinderArgumentResolvers 和 returnValueHandlers 初始化过程中都调用了相应的getDefaultXXX方法,下以getDefaultArgumentResolvers()为例:

//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
		List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();

		// 添加按"注释"解析参数的解析器
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
		resolvers.add(new RequestParamMapMethodArgumentResolver());
		resolvers.add(new PathVariableMethodArgumentResolver());
		resolvers.add(new PathVariableMapMethodArgumentResolver());
		resolvers.add(new MatrixVariableMethodArgumentResolver());
		resolvers.add(new MatrixVariableMapMethodArgumentResolver());
		resolvers.add(new ServletModelAttributeMethodProcessor(false));
		resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters()));
		resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters()));
		resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new RequestHeaderMapMethodArgumentResolver());
		resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));

		 添加按"类型"解析参数的解析器
		resolvers.add(new ServletRequestMethodArgumentResolver());
		resolvers.add(new ServletResponseMethodArgumentResolver());
		resolvers.add(new HttpEntityMethodProcessor(getMessageConverters()));
		resolvers.add(new RedirectAttributesMethodArgumentResolver());
		resolvers.add(new ModelMethodProcessor());
		resolvers.add(new MapMethodProcessor());
		resolvers.add(new ErrorsMethodArgumentResolver());
		resolvers.add(new SessionStatusMethodArgumentResolver());
		resolvers.add(new UriComponentsBuilderMethodArgumentResolver());

		//添加自定义参数解析器, 主要用于解析自定义类型
		if (getCustomArgumentResolvers() != null) {
			resolvers.addAll(getCustomArgumentResolvers());
		}

		//最后两个解析器: 可以解析所有解析类型
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
		resolvers.add(new ServletModelAttributeMethodProcessor(true));

		return resolvers;
	}

可以看到上述有四类解析器:其中第三类为自定义解析器,通过自定义HandlerMethodArgumentResolver实现,然后通过customArgumentResolvers属性注册到RequestMappingHandlerAdapter中。
注意: 自定义解析器的优先级必须在前两种解析器无法解析时才会使用到,这个顺序无法改变!

例:如果自定义一个解析器用来解析@PathVariable注释的参数,是无法实现的,因为它会前两种解析器解析。


RequestMappingHandlerAdapter 调用

RequestMappingHandlerAdapter处理请求的入口方法是handleInternal,代码如下:

//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
protected ModelAndView handleInternal(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    /**
     * getSessionAttributesHandler: 判断handlerMethod是否有@SessionAttributes注解,
     * SessionAttributesHandler.hasSessionAttributes(): 判断@SessionAttributes注解,是否有value,types 属性配置
     **/
    if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
        checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
    } else {
        checkAndPrepare(request, response, true);
    }

    if (this.synchronizeOnSession) {
        HttpSession session = request.getSession(false);
        if (session != null) {
            Object mutex = WebUtils.getSessionMutex(session);
            synchronized (mutex) {
                return invokeHandleMethod(request, response, handlerMethod);
            }
        }
    }

    return invokeHandleMethod(request, response, handlerMethod);
}

checkAndPrepare
checkAndPrepare 方法在父类 WebContentGenerator中定义;

//AbstractHandlerMethodAdapter 继承 WebContentGenerator ,
public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
    public AbstractHandlerMethodAdapter() {
		super(false);
	}
}

public abstract class WebContentGenerator extends WebApplicationObjectSupport {
    //restrictDefaultSupportedMethods: 是否限制Http方法类型,默认为false;
    public WebContentGenerator(boolean restrictDefaultSupportedMethods) {
        if (restrictDefaultSupportedMethods) {
            this.supportedMethods = new HashSet<String>(4);
            this.supportedMethods.add(METHOD_GET);
            this.supportedMethods.add(METHOD_HEAD);
            this.supportedMethods.add(METHOD_POST);
        }
    }
    
    protected final void checkAndPrepare(HttpServletRequest request, HttpServletResponse response, boolean lastModified)  {
        checkAndPrepare(request, response, -1 , lastModified);
    }
    
    protected final void checkAndPrepare(HttpServletRequest request, HttpServletResponse response, int cacheSeconds, boolean lastModified) {
        String method = request.getMethod();
         // 判断是否支持method :: 默认不限制http方法类型 restrictDefaultSupportedMethods = false
        if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {
            throw new HttpRequestMethodNotSupportedException(method, StringUtils.toStringArray(this.supportedMethods));
        }

        // 判断是否必须session, 默认为false;
        if (this.requireSession) {
            if (request.getSession(false) == null) {
                throw new HttpSessionRequiredException("Pre-existing session required but none found");
            }
        }

        /**
         * 给response设置缓存过期时间
         * cacheSeconds > 0 : 设置缓存具体时间。 单位s
         * cacheSeconds = 0 :  禁止使用缓存,对response的setHeader进行`"no-cache"`设置;
         * cacheSeconds = -1 : do nothing
         */
        applyCacheSeconds(response, cacheSeconds, lastModified);
    }
}    		

checkAndPrepare方法的作用:用来设置response缓存相关的Header参数。


invokeHandleMethod
invokeHandleMethod,它执行请求的处理。

//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
private ModelAndView invokeHandleMethod(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) {
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    
    /**
     * 寻找handlerMethod对应的InitBinderMethod ,
     * 先@ControllerAdvice中配置的全局@InitBinder的Method,
     * 后自身@InitBinder的Method 后createDataBinderFactory
     */
    WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
    
    /**
     * 寻找@SessionAttributes,@ControllerAdvice中配置的全局@ModelAttribute方法 和自身的@ModelAttribute方法,
     * 加上上一步的binderFactory,创建ModelFactory
     */
    ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
    
    //创建ServletInvocableHandlerMethod,实际请求的执行包括:参数绑定,处理请求以及返回值处理都在此类中完成。
    ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);
    
    ModelAndViewContainer mavContainer = new ModelAndViewContainer();
    //将FlashMap中数据设置到model中
    mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
    //使用mdoelFactory将 @ModelAttribute 和 @SessionAttributes参数设置到Model.
    modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
    mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

   //.....省略 async部分代码......
   
   //执行请求, 后续ServletInvocableHandlerMethod详解
    requestMappingMethod.invokeAndHandle(webRequest, mavContainer);

    /*
     * modelFactory更新model(包括SessionAttributes 和 给Model设置BindingResult)
     * mavContainer 创建 ModelAndView
     * mavContainer中的model如果是RedirectAttributes类型,则将值设置到FlashMap中。
     */
    return getModelAndView(mavContainer, modelFactory, webRequest);
}

自此整个RequestMappingHandlerAdapter处理请求的过程(不包含各个组件的内部处理逻辑)就分析完成了,接下来分析各个组件的处理过程。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值