Spring 源码解析之HandlerAdapter源码解析(二)

Spring 源码解析之HandlerAdapter源码解析(二)

前言

看这篇之前需要有Spring 源码解析之HandlerMapping源码解析(一)这篇的基础,这篇主要是把请求流程中的调用controller流程单独拿出来了

解决上篇文章遗留的问题

  1. getHandler(processedRequest) 这个方法是如何查找到对应处理的HandlerExecutionChain和HandlerMapping的,比如说静态资源的处理和请求的处理肯定是不同的HandlerMapping
  2. getHandlerAdapter(mappedHandler.getHandler());如果取到对应的HandlerAdapter

问题一

先来看DispatcherServlet中HandlerMapping初始化,从下属代码看来,其实HandlerMapping的初始化工作并不在DispatcherServlet,而是在Spring初始化的地方,这里只不过是把所有的HandlerMapping加载到DispatcherServlet中,并且排序生成集合


private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;

        if (this.detectAllHandlerMappings) {
            // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
            //这里从BeanFactory中获取已经初始化好的HandlerMapping
            Map<String, HandlerMapping> matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
                // We keep HandlerMappings in sorted order.
                //对handlerMappings进行排序
                AnnotationAwareOrderComparator.sort(this.handlerMappings);
            }
        }
        else {
            try {
                HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
                this.handlerMappings = Collections.singletonList(hm);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, we‘ll add a default HandlerMapping later.
            }
        }

        // Ensure we have at least one HandlerMapping, by registering
        // a default HandlerMapping if no other mappings are found.
        if (this.handlerMappings == null) {
            this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
            if (logger.isDebugEnabled()) {
                logger.debug("No HandlerMappings found in servlet ‘" + getServletName() + "‘: using default");
            }
        }
    }

接下来是查找适合的HandlerExecutionChain,从代码来看,上面的排序代码AnnotationAwareOrderComparator.sort(this.handlerMappings);是有很大用处的,从这段代码逻辑来看,其实是通过for循环优先找到排在最前面并且适合的HandlerExecutionChain,从上一篇《Spring 源码解析之HandlerMapping源码解析(一)》文章可知,我这里大概初始化了十种处理请求的handlerMappings,普通的页面请求和json请求都是通过RequestMappingHandlerMapping进行处理的

//DispatcherServlet中的getHandler
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        for (HandlerMapping hm : this.handlerMappings) {
            if (logger.isTraceEnabled()) {
                logger.trace(
                        "Testing handler map [" + hm + "] in DispatcherServlet with name ‘" + getServletName() + "‘");
            }
            HandlerExecutionChain handler = hm.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
        return null;
    }

//RequestMappingHandlerMapping的父类AbstractHandlerMapping中实现了getHandler方法
@Override
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //调用子类AbstractHandlerMethodMapping getHandlerInternal()
        Object handler = getHandlerInternal(request);
        //如果没有获取到,就使用默认的
        if (handler == null) {
            handler = getDefaultHandler();
        }
        //如果默认的没有定义就返回null
        if (handler == null) {
            return null;
        }
        //说实话当时我看到源码里面的注释,当时我内心是崩溃的,Spring开发人员自己都不知道这个代码是做什么的,你难道是问我 - -
        //你tm一定是在逗我
        // Bean name or resolved handler?(这个英文注释是开发人员自己写的,不是我写上去的)
        //反正大概意思就是handler如果定义了一个字符串,那么根据这个name去查找Handler
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }
        //根据handlermethod获取相应的拦截器处理调用链
        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
        if (CorsUtils.isCorsRequest(request)) {
            CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
            CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
            CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
            executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
        }
        return executionChain;
    }
 //AbstractHandlerMethodMapping 中实现AbstractHandlerMapping getHandlerInternal方法,去获取HandlerMethod
    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        //获取访问路径比如定义了路径/admin/login
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        if (logger.isDebugEnabled()) {
            logger.debug("Looking up handler method for path " + lookupPath);
        }
        //获取可读锁,暂时不知道用意在哪里
        this.mappingRegistry.acquireReadLock();
        try {
            HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
            if (logger.isDebugEnabled()) {
                if (handlerMethod != null) {
                    logger.debug("Returning handler method [" + handlerMethod + "]");
                }
                else {
                    logger.debug("Did not find handler method for [" + lookupPath + "]");
                }
            }
            return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
        }
        finally {
            //解锁
            this.mappingRegistry.releaseReadLock();
        }
    }
//AbstractHandlerMethodMapping 中根据路径查询到相应的Controller方法
    protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
        List<Match> matches = new ArrayList<Match>();
        //从注册的mappingRegistry中获取直接符合的
        List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
        //如果不等于null,添加符合的进去
        if (directPathMatches != null) {
            addMatchingMappings(directPathMatches, matches, request);
        }
        if (matches.isEmpty()) {
            // No choice but to go through all mappings...
            addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
        }

        if (!matches.isEmpty()) {
            Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
            Collections.sort(matches, comparator);
            if (logger.isTraceEnabled()) {
                logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
                        lookupPath + "] : " + matches);
            }
            //排序后取第一个符合的
            Match bestMatch = matches.get(0);
          //如果符合处理请求HandlerMethod的数量大于1
            if (matches.size() > 1) {
                if (CorsUtils.isPreFlightRequest(request)) {
                    return PREFLIGHT_AMBIGUOUS_MATCH;
                }
                //判断第一个和第二个符合的,如果都一样 那么就抛出异常
                Match secondBestMatch = matches.get(1);
                if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                    Method m1 = bestMatch.handlerMethod.getMethod();
                    Method m2 = secondBestMatch.handlerMethod.getMethod();
                    throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path ‘" +
                            request.getRequestURL() + "‘: {" + m1 + ", " + m2 + "}");
                }
            }
            // 存入request的attribute中,具体有什么用不太了解request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, lookupPath);
            handleMatch(bestMatch.mapping, lookupPath, request);
            //获取handlerMethod
            return bestMatch.handlerMethod;
        }
        else {
            return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
        }
    }

 //AbstractHandlerMapping中获取HandlerExecutionChain调用链
    protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
        for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
            if (interceptor instanceof MappedInterceptor) {
                MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
                if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                    chain.addInterceptor(mappedInterceptor.getInterceptor());
                }
            }
            else {
                chain.addInterceptor(interceptor);
            }
        }
        return chain;
    }

大致流程如上面代码,所示其实核心无非就是把url和controller里面的method关联起来,通过查找去找到合适的

问题二

如何根据合适的找到合适的HandlerAdapter,看看下面代码

//初始化就不继续讲拉,跟handpermapping一模一样,也是经过排序后的
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    //遍历所有的handlerAdapters
        for (HandlerAdapter ha : this.handlerAdapters) {
            if (logger.isTraceEnabled()) {
                logger.trace("Testing handler adapter [" + ha + "]");
            }
            //调用相应实现的support方法,排在最前面的优先调用
            if (ha.supports(handler)) {
                return ha;
            }
        }
        throw new ServletException("No adapter for handler [" + handler +
                "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }
    //比如说`RequestMappingHandlerAdapter`的实现如下 ,用instanceof 来判断是否是HandlerMethod即可
    @Override
    public final boolean supports(Object handler) {
        return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
    }
    @Override
    protected boolean supportsInternal(HandlerMethod handlerMethod) {
        return true;
    }

从上面看来,其实想定义自己的HandlerAdapter也是可以的,只要把排序的Order设置大一些,优先找到自定义的HandlerAdapter即可

HandlerAdapter功能介绍

这里再次详细介绍一下HandlerAdapter,HandlerAdapter实现大概分为以下几种

1.RequestMappingHandlerAdapter(3.1之前是AnnotationMethodHandlerAdapter)

这里我就直接先分析RequestMappingHandlerAdapter,大致类图如上所示,RequestMappingHandlerAdapter主要作用是调用相应的HandlerMethod,并把参数封装成具体method需要的格式,初始化的时候RequestMappingHandlerAdapter默认加载了如下的参数解析方式

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
        List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
        // Annotation-based argument resolution
    //添加RequestParam 普通的参数解析@RequestParam 注解参数,但不处理参数类型为Map,且不包含value值
        resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
    //Resolves {@link Map} method arguments annotated with an @{@link RequestParam}
    //上述英文描述,大致就是说把参数解析成map的Resolver,解决了RequestParamMethodArgumentResolver不能解析成map的缺点
        resolvers.add(new RequestParamMapMethodArgumentResolver());
    //PathVariableMethod这个经常用spring的都知道,其实就是路径里面的参数,restful风格的参数
        resolvers.add(new PathVariableMethodArgumentResolver());
    //处理是参数类型是map的情况
    /**  @RequestMapping(value = "/index/article/{id:\\d+}",  produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String getArticleDetail(@PathVariable Map map) {
        int id=0;
    */
    //比如上面的id 转换到map中,就是key为 id value为具体值
        resolvers.add(new PathVariableMapMethodArgumentResolver());
    //spring 3.2后增加的注解@MatrixVariable的解析,是 @PathVariable的一种辅助注解,具体可以百度下看看使用方式
        resolvers.add(new MatrixVariableMethodArgumentResolver());
        resolvers.add(new MatrixVariableMapMethodArgumentResolver());
    //Also adds a fall-back strategy to instantiate the model attribute from a URI template variable or from a request parameter if the name matches the model attribute name and there is an appropriate type conversion strategy.
    //上述英文是Spring文档里面对这个类的描述,大概意思就是request的attribute name名跟model的属性名相同的时候
        resolvers.add(new ServletModelAttributeMethodProcessor(false));
    //@RequestBody和@ResponseBody 注解的解析
        resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
    //Supported method argument types include MultipartFile
    //这个主要是文件上传的解析,文件上传的时候可以指定名字,支持@RequestPart
        resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
    //支持@RequestHeader
        resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
    //支持@RequestHeader map参数类型
        resolvers.add(new RequestHeaderMapMethodArgumentResolver());
    //支持Cookie参数
        resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
    //支持注解@Value
        resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));

    //上面都是基于注解的解析,下面都是基于参数名称的解析
        // Type-based argument resolution
    /**
    Resolves request-related method argument values of the following types:
    WebRequest
    ServletRequest
    MultipartRequest
    HttpSession
    Principal
    Locale
    TimeZone (as of Spring 4.0)
    ZoneId (as of Spring 4.0 and Java 8)
    InputStream
    Reader
    HttpMethod (as of Spring 4.0)
    **/
    //这个主要是解析上面的参数
        resolvers.add(new ServletRequestMethodArgumentResolver());
    //处理返回类型
    /**
    * ServletResponse
    * OutputStream
    * Writer
    **/
        resolvers.add(new ServletResponseMethodArgumentResolver());
    //解析 HttpEntity RequestEntity
        resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
    //Resolves  RedirectAttributes
        resolvers.add(new RedirectAttributesMethodArgumentResolver());
    //Resolves  Model arguments and handles  Model return values
    //解析Model参数
        resolvers.add(new ModelMethodProcessor());
    //Resolves  Map method arguments and handles  Map return values.
        resolvers.add(new MapMethodProcessor());
    // Resolves Errors method arguments
        resolvers.add(new ErrorsMethodArgumentResolver());
    //Resolves a SessionStatus argument
        resolvers.add(new SessionStatusMethodArgumentResolver());
    // Resolvers argument values of type  UriComponentsBuilder
        resolvers.add(new UriComponentsBuilderMethodArgumentResolver());

        // Custom arguments
    //这里可以自己实现getCustomArgumentResolvers() 去定义自己的参数实现
        if (getCustomArgumentResolvers() != null) {
            resolvers.addAll(getCustomArgumentResolvers());
        }

        // Catch-all
    //Resolves method arguments annotated with  @RequestParam
        resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
    //Resolves 参数包含注解ModelAttribute
        resolvers.add(new ServletModelAttributeMethodProcessor(true));

        return resolvers;
    }

通过上述的代码表明,RequestMappingHandlerAdapter封装了所有的参数解析,继续看核心内容,handlerAdapter对方法的调用逻辑如下

@Override
    protected ModelAndView handleInternal(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

        ModelAndView mav = null;
    //校验该请求的method是否支持, 也就是这上面支持的方法@RequestMapping(value = "edit/save", method = RequestMethod.POST)
        checkRequest(request);

        // Execute invokeHandlerMethod in synchronized block if required.
    //是否采用session 锁,这块暂时没有找到在哪用,倒是可以通过配置bean的方式来实现,下面是 英文的解释
    /**
    Set if controller execution should be synchronized on the session, to serialize parallel invocations from the same client.
    More specifically, the execution of the handleRequestInternal method will get synchronized if this flag is "true". The best available session mutex will be used for the synchronization; ideally, this will be a mutex exposed by HttpSessionMutexListener.

    The session mutex is guaranteed to be the same object during the entire lifetime of the session, available under the key defined by the SESSION_MUTEX_ATTRIBUTE constant. It serves as a safe reference to synchronize on for locking on the current session.

    In many cases, the HttpSession reference itself is a safe mutex as well, since it will always be the same object reference for the same active logical session. However, this is not guaranteed across different servlet containers; the only 100% safe way is a session mutex.
    */
        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized (mutex) {
          //具体的方法调用处
                    mav = invokeHandlerMethod(request, response, handlerMethod);
                }
            }
        }
    //这块感觉跟上面的逻辑有点重复,如果加了锁并且锁住了上面执行一遍invokeHandlerMethod 这里还会执行一遍invokeHandlerMethod,无论做了什么操作,性能上会有一些下降吧,个人看法
        mav = invokeHandlerMethod(request, response, handlerMethod);

        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
        }
        else {
            prepareResponse(response);
        }

        return mav;
    }

invokeHandlerMethod(request, response, handlerMethod) 是具体调用Controller的部分


protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
      ///包装一下request, response 提供一些操作方法
        ServletWebRequest webRequest = new ServletWebRequest(request, response);
    //获取到DataBinderFactory(这里创建的是ServletRequestDataBinderFactory) 也就是经常使用的@InitBinder,这里以后会单独留一个模块出来进行讲解
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
    //Provides methods to initialize the  Model before controller method invocation and to update it afterwards
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        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();
            if (logger.isDebugEnabled()) {
                logger.debug("Found concurrent result value [" + result + "]");
            }
            invocableMethod = invocableMethod.wrapConcurrentResult(result);
        }

        //这里调用具体的方法
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }
        //返回响应的ModelAndView对象
        return getModelAndView(mavContainer, modelFactory, webRequest);
    }

上面调用了invocableMethod.invokeAndHandle(webRequest, mavContainer),这个方法在ServletInvocableHandlerMethod中具体实现如下


public void invokeAndHandle(ServletWebRequest webRequest,
            ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
        //调用invokeForRequest实现去具体调用controller方法
        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        //设置response状态
        setResponseStatus(webRequest);

        if (returnValue == null) {
            if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
                mavContainer.setRequestHandled(true);
                return;
            }
        }
        else if (StringUtils.hasText(this.responseReason)) {
            mavContainer.setRequestHandled(true);
            return;
        }

        mavContainer.setRequestHandled(false);
        try {
            this.returnValueHandlers.handleReturnValue(
                    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }
        catch (Exception ex) {
            if (logger.isTraceEnabled()) {
                logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
            }
            throw ex;
        }
    }
    //主要解析方法参数,然后调用真正的反射方法
    public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
                Object... providedArgs) throws Exception {
            //通过之前的参数解析器把参数解析成相应的各个对象
            Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
            if (logger.isTraceEnabled()) {
                StringBuilder sb = new StringBuilder("Invoking [");
                sb.append(getBeanType().getSimpleName()).append(".");
                sb.append(getMethod().getName()).append("] method with arguments ");
                sb.append(Arrays.asList(args));
                logger.trace(sb.toString());
            }
            //进行方法的调用
            Object returnValue = doInvoke(args);
            if (logger.isTraceEnabled()) {
                logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");
            }
            return returnValue;
        }
        //doInvoke才是真正调用方法的地方
        protected Object doInvoke(Object... args) throws Exception {
            //先通过设置方法的访问权限,用过反射的都知道先setAccessible为true
                ReflectionUtils.makeAccessible(getBridgedMethod());
                try {
                    //执行调用
                    return getBridgedMethod().invoke(getBean(), args);
                }
                catch (IllegalArgumentException ex) {
                    assertTargetBean(getBridgedMethod(), getBean(), args);
                    String message = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
                    throw new IllegalStateException(getInvocationErrorMessage(message, args), ex);
                }
                catch (InvocationTargetException ex) {
                    // Unwrap for HandlerExceptionResolvers ...
                    Throwable targetException = ex.getTargetException();
                    if (targetException instanceof RuntimeException) {
                        throw (RuntimeException) targetException;
                    }
                    else if (targetException instanceof Error) {
                        throw (Error) targetException;
                    }
                    else if (targetException instanceof Exception) {
                        throw (Exception) targetException;
                    }
                    else {
                        String msg = getInvocationErrorMessage("Failed to invoke controller method", args);
                        throw new IllegalStateException(msg, targetException);
                    }
                }
            }

2.SimpleServletHandlerAdapter

看名字就能够大致猜到这个类的作用,SimpleServletHandlerAdapter 从翻译上来说叫做简单的Servlet处理适配器,源码如下所示,看起来确实没有几句代码,大致英文解释(Adapter to use the Servlet interface with the generic DispatcherServlet.Calls the Servlet’s {@code service} method to handle a request)。大概就是说可以用Spring去管理Servlet,这样就可以在Spring中使用Servlet,这就是说Servlet可以使用ioc和aop的一些功能了,但是感觉这样的使用场景并不多,所以也很少使用,其次还有另外一种使用Spring管理Servlet的方式,就是采用全注解配置DispatcherServlet的方式,所以感觉这个adapter没有太大用处


public class SimpleServletHandlerAdapter implements HandlerAdapter {

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

    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        ((Servlet) handler).service(request, response);
        return null;
    }

    @Override
    public long getLastModified(HttpServletRequest request, Object handler) {
        return -1;
    }

}

参照网上的实习代码如下所示,servlet的bean name代表了请求路径:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:ehcache="http://www.springmodules.org/schema/ehcache"
    xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
            http://www.springmodules.org/schema/ehcache http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd"
            default-lazy-init="true">  

    <!--启用注解   定义组件查找规则 -->
    <context:component-scan base-package="com.demo">
        <context:include-filter type="annotation"
            expression="org.springframework.stereotype.Service" />
    </context:component-scan>  

    <!-- servlet适配器,这里必须明确声明,因为spring默认没有初始化该适配器 -->
    <bean id="servletHandlerAdapter" class="org.springframework.web.servlet.handler.SimpleServletHandlerAdapter"/>  

    <!-- demo servlet -->
    <bean name="/demo.do" class="com.demo.DemoServlet"/>  

</beans>

3.SimpleControllerHandlerAdapter

The Controller interface is explicitly designed to operate on HttpServletRequest and HttpServletResponse objects, just like an HttpServlet. It does not aim to decouple itself from the Servlet API

上面英文大概意思就是,让Controller的用法像使用servlet一样,需要Controller实现Controller接口,实现代码如下,无非就是直接调用Controller方法

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

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

    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        return ((Controller) handler).handleRequest(request, response);
    }

    @Override
    public long getLastModified(HttpServletRequest request, Object handler) {
        if (handler instanceof LastModified) {
            return ((LastModified) handler).getLastModified(request);
        }
        return -1L;
    }

}

总结

本文在这次介绍中总共留下几个流程没有讲述,在接下来的里面会更详细的介绍

1. WebDataBinderFactory 也就是@InitBinder实现的流程?

2. WebAsyncManager 和AsyncWebRequest 这些都是异步请求的管理?

3. Spring是如何知道请求对应Controller的方法的?

4. Spring模板的渲染机制?

其他地方如果读者有问题可以随时联系,你的问题也许是我没有考虑到的地方。

时间: 2024-10-24 15:22:33

Spring 源码解析之HandlerAdapter源码解析(二)的相关文章

spring MVC cors跨域实现源码解析 CorsConfiguration UrlBasedCorsConfigurationSource

spring MVC cors跨域实现源码解析 名词解释:跨域资源共享(Cross-Origin Resource Sharing) 简单说就是只要协议.IP.http方法任意一个不同就是跨域. spring MVC自4.2开始添加了跨域的支持. 跨域具体的定义请移步mozilla查看 使用案例 spring mvc中跨域使用有3种方式: 在web.xml中配置CorsFilter <filter> <filter-name>cors</filter-name> <

Spring mvc之源码 handlerMapping和handlerAdapter分析

Spring mvc之源码 handlerMapping和handlerAdapter分析 本篇并不是具体分析Spring mvc,所以好多细节都是一笔带过,主要是带大家梳理一下整个Spring mvc的执行流程,以及如何根据URL查找处理器Controller的实现 (适合那些刚阅读源码不知道如何下手的人) http://www.guojinbao.com/borrow/borrowDetail/GETadLPjnf0[d].do 如何根据URL地址---->找到正确处理器Controller

Spring 源码解析之ViewResolver源码解析(四)

Spring 源码解析之ViewResolver源码解析(四) 1 ViewResolver类功能解析 1.1 ViewResolver Interface to be implemented by objects that can resolve views by name. View state doesn't change during the running of the application, so implementations are free to cache views. I

Spring 源码解析之DispatcherServlet源码解析(五)

Spring 源码解析之DispatcherServlet源码解析(五) 前言 本文需要有前四篇文章的基础,才能够清晰易懂,有兴趣可以先看看详细的流程,这篇文章可以说是第一篇文章,也可以说是前四篇文章的的汇总,Spring的整个请求流程都是围绕着DispatcherServlet进行的 类结构图 根据类的结构来说DispatcherServlet本身也是继承了HttpServlet的,所有的请求都是根据这一个Servlet来进行转发的,同时解释了为什么需要在web.xml进行如下配置,因为Spr

Spring源码解析——如何阅读源码

最近没什么实质性的工作,正好有点时间,就想学学别人的代码.也看过一点源码,算是有了点阅读的经验,于是下定决心看下spring这种大型的项目的源码,学学它的设计思想. 手码不易,转载请注明:xingoo 这篇博文你可以了解到: 1 Spring jar包以及源码使用 2 简单的spring运行示例 3 利用断点调试程序,如何快速的阅读程序[快捷键等的使用] 这次阅读的源码比较老了,是3.0.5版本的,由于正好手头有这个版本的源码,而且平时基本上也是用的这个版本Spring,因此后文的分析也都是针对

Spring源码解析——如何阅读源码(转)

最近没什么实质性的工作,正好有点时间,就想学学别人的代码.也看过一点源码,算是有了点阅读的经验,于是下定决心看下spring这种大型的项目的源码,学学它的设计思想. 手码不易,转载请注明:xingoo 这篇博文你可以了解到: 1 Spring jar包以及源码使用 2 简单的spring运行示例 3 利用断点调试程序,如何快速的阅读程序[快捷键等的使用] 这次阅读的源码比较老了,是3.0.5版本的,由于正好手头有这个版本的源码,而且平时基本上也是用的这个版本Spring,因此后文的分析也都是针对

Spring源码学习(三)默认标签的解析

默认标签的解析分为四种:import,alias,bean,beans,在下面函数中进行 1 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { 2 if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { 3 importBeanDefinitionResource(ele); 4 } 5 else if (delegate.n

Spring源码学习(四)自定义标签的解析

新的一年 只争朝夕 不负韶华 加油加油?? (一)自定义便签使用 步骤:(前提要将Spring Core包加入项目中) (1)创建需要扩展的组件 (2)定义一个XSD文件描述组件内容 (3)创建一个文件,实现BeanDefinitionParse接口,用来解析XSD文件中的定义和组件定义 (4)创建一个Handler文件,扩展自NamespaceHandleSupport,目的是将组件注册到Spring容器 (5)编写Spring.Handlers和Spring.schemas文件 具体代码如下

struct2源码解读(3)之解析配置文件

struct2源码解读之解析配置文件 上篇博文讲到struct2在初始化时,在创建Dispacher之后,会Dispacher.init()中会对配置文件进行解析,下面就让我们一起探讨下struct2是如何解析配置文件的. public Dispatcher initDispatcher( HostConfig filterConfig ) {           //创建Dispacher实例         Dispatcher dispatcher = createDispatcher(f