RestTemplate的使用和原理你都烂熟于胸了吗?【享学Spring MVC】

每篇一句

人圆月圆心圆,人和家和国和---中秋节快乐

前言

在阅读本篇之前,建议先阅读开山篇效果更佳。RestTemplate是Spring提供的用于访问Rest服务的客户端工具,它提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率
弱弱呼吁一句:对于那些在Spring环境下还在使用HttpClient(或其它Client)的同学,今儿看完本文后,建议切换到RestTemplate (有特殊需求的当然除外喽~)。

RestTemplate简化了与http服务的通信,程序代码可以给它提供URL,并提取结果。它默认使用的JDK 的HttpURLConnection进行通信,然而我们是可以通过RestTemplate.setRequestFactory切换到不同的HTTP源:如Apache HttpComponentsNettyOkHttp等等。

RestOperations

指定一组基本restful操作的接口,定义了基本的Rest操作集合,它的唯一实现是RestTemplate;不直接使用,但这是增强可测试性的一个有用选项,因为它很容易被模拟或存根(后面这句话请好好理解)。

可以对比参照RedisOperations,它的实现类也只有RedisTemplate一个。他俩都采用了设计模式中的模板模式

方法们:

由于此接口里的方法实在太多了(40+个),因此我按照Http标准进行分类如下表格:

// @since 3.0
public enum HttpMethod {
    GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;
    ...
}
HttpMethod 方法
GET
HEAD
POST
PUT
PATCH
DELETE
OPTIONS
TRACE
any(执行任何Http方法)

观察发现,虽然方法众多但有很强的规律可循。每个方法都有三种重载实现:2种的url参数为字符串,一种URI参数,所以掌握规律后再使用,就不用害怕它的多而不知咋使用了。

xxxForObject:返回响应体(也就直接是body体力的内容) (T)
xxxForEntity:返回的相应行、响应头、响应码、响应体等等 (ResponseEntity)
xxxForLocation:提交成功之后,返回新资源的URI。这个只需要服务提供者返回一个 URI 即可,该 URI 表示新资源的位置,可谓非常轻量。 (URI)

注意:使用字符串类型的url默认会对url进行转义,如http://example.com/hotel list在执行时会转义为http://example.com/hotel%20list,隐式的转义这样是没有问题的。但如果你自己已经转义过了,那就不ok了。
若不想要这种隐式的转义,建议使用URI(URI uri = uriComponents.toUri())来构造。

==RestTemplate中POST请求的三种方式==

post请求代表新建/创建一个资源,所以它是有返回值的。因为它的使用最为复杂,因此本文以它为例进行讲解。

你如果熟练使用过浏览器的开发者工具调试过,你肯定知道POST请求它传参是有两种方式的:

  1. Form Data方式:我们用from表单提交的方式就是它;使用ajax(注意:这里指的是jQuery的ajax,而不是源生js的)默认的提交方式也是它~
  2. request payload方式:多部分方式/json方式

这两种方式是通过Content-Type来区别的:若是application/x-www-form-urlencoded那就是formdata方式;若是application/json或者multipart/form-data等方式那就是request payload方式

jQuery在执行post请求时,默认会给你设置Content-Typeapplication/x-www-form-urlencoded,所以服务器能够正确解析。
若使用js原生的ajax,如果不显示的设置Content-Type,那么默认是text/plain,这时服务器就不知道怎么解析数据了,所以才只能通过获取原始数据流的方式来进行解析请求数据。(相信没人这么干吧~)

exchange和execute方法:

exchange方法:更通用的请求方法。它入参必须接受一个RequestEntity,从而可以设置请求的路径、头等等信息,最终全都是返回一个ResponseEntity(可以发送Get、Post、Put等所有请求)。
execute方法:最最最底层、通用的请求方法。

RequestCallback:用于操作请求头和body,在请求发出执行;ResponseExtractor:解析/提取HTTP响应的数据,而且不需要担心异常和资源的关闭
RequestCallback.doWithRequest(ClientHttpRequest)说白了就是拿到ClientHttpRequest后对他进行继续处理~
RestTemplateacceptHeaderRequestCallback、httpEntityCallback这些方法可以设置它~
---

HttpAccessor、InterceptingHttpAccessor

这两个抽象类不容忽视,HystrixCommand和Ribbon的逻辑都和它有关系(拦截器)。
HttpAccessor是个抽象基类,它定义要操作ClientHttpRequestFactory的公共属性,它一般不直接使用。

// @since 3.0
public abstract class HttpAccessor {

    // RestTemplate默认使用的客户端工厂:基于源生JDK
    private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

    // 若要切换成三方库的底层组件,设置此方法便可
    public void setRequestFactory(ClientHttpRequestFactory requestFactory) {
        this.requestFactory = requestFactory;
    }
    ... // get方法

    // 供给子类非常方便的拿到一个ClientHttpRequest
    protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
        ClientHttpRequest request = getRequestFactory().createRequest(url, method);
        return request;
    }
}

它的子类是:InterceptingHttpAccessor,也还是个抽象实现,主要是管理起了请求的拦截器们:ClientHttpRequestInterceptor

InterceptingHttpAccessor

// @since 3.0
// @see InterceptingClientHttpRequestFactory
public abstract class InterceptingHttpAccessor extends HttpAccessor {

    // 装载需要作用在RestTemplate上的拦截器们~~~
    private final List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
    @Nullable
    private volatile ClientHttpRequestFactory interceptingRequestFactory;

    // 这里语意是set,所以是完全的替换掉(支持ordered排序哦~~~)
    public void setInterceptors(List<ClientHttpRequestInterceptor> interceptors) {
        if (this.interceptors != interceptors) {
            this.interceptors.clear();
            this.interceptors.addAll(interceptors);
            AnnotationAwareOrderComparator.sort(this.interceptors);
        }
    }

    // 复写了父类的这个方法很有意思
    // 意思为:若你调用者手动set进来了,那就以调用者设置的工厂为准 否则使用的是InterceptingClientHttpRequestFactory
    @Override
    public void setRequestFactory(ClientHttpRequestFactory requestFactory) {
        super.setRequestFactory(requestFactory);
        this.interceptingRequestFactory = null;
    }

    // 若配置了拦截器,那么默认就使用InterceptingClientHttpRequestFactory,而不再是SimpleClientHttpRequestFactory了~~~
    @Override
    public ClientHttpRequestFactory getRequestFactory() {
        List<ClientHttpRequestInterceptor> interceptors = getInterceptors();
        if (!CollectionUtils.isEmpty(interceptors)) {
            ClientHttpRequestFactory factory = this.interceptingRequestFactory;
            if (factory == null) {
                factory = new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
                this.interceptingRequestFactory = factory;
            }
            return factory;
        } else {
            return super.getRequestFactory();
        }
    }
}

InterceptingHttpAccessor最主要的处理逻辑为:若发现调用者设置了请求拦截器,那么它创建的工厂是具有拦截功能的InterceptingClientHttpRequestFactory,否则就是默认的SimpleClientHttpRequestFactory

InterceptingClientHttpRequestFactory工厂它产生的ClientHttpRequestInterceptingClientHttpRequest,然而它就会执行拦截器的拦截方法喽:nextInterceptor.intercept(request, body, this)

提问:如有配置有多个请求拦截器,都会执行吗?
解答:这个千万不要犯迷糊和轻易下结论:以为没有迭代它(for循环)而只是iterator.next()就以为若有多个就只会执行一个,那就大错特错了。这里实际是形成了一个执行链条,只要拦截器的intercept方法内最终还调用执行器的intercept()方法,那么拦截器链就会一直执行下去。其根本缘由是第三个参数传入的是this,至始至终都是同一个执行器(this=InterceptingRequestExecution

---


==RestTemplate==

RestTemplate采用同步方式执行 HTTP 请求的类,底层默认使用JDK原生 HttpURLConnection API。它实现了接口RestOperations,提供了非常多的模版方法(重载方法)让开发者能更简单地发送 HTTP 请求。

需要注意的是,RestTemplateSpring 3.0就有了,但在Spring5.0后,Spring官方是推荐使用org.springframework.web.reactive.function.client.WebClient替代它,特别是对于异步的场景。

RestTemplate因为使用极其广泛,so即使到了Spring 5.0,官方只是建议替代,但并没有标注@Deprecated,因此至少目前你还可以想咋用就咋用吧。
但是AsyncRestTemplate是明确标注了@Deprecated,强烈建议使用org.springframework.web.reactive.function.client.WebClient去代替,所以在5.0后不建议再使用它了~。

当然还需要说明一点:若你的项目中没有使用到WebFlux的技术栈来处理请求,那么也没必要说为了使用而使用,所以没必要专门为了它而导包(个人建议)~

// @since 3.0
public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {
    // 去classpath探测  是否有这些消息转换器相关的jar~
    // 一般情况下我们都会导jackson2Present~~~
    private static boolean romePresent;
    private static final boolean jaxb2Present;
    private static final boolean jackson2Present;
    private static final boolean jackson2XmlPresent;
    private static final boolean jackson2SmilePresent;
    private static final boolean jackson2CborPresent;
    private static final boolean gsonPresent;
    private static final boolean jsonbPresent;
    ...

    // 下面四个变量很重要:

    // 消息转换器们(显然对JSON格式默认是支持得最好的)
    private final List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
    // 默认的请求异常处理器,Spring5.0后其实可以使用它ExtractingResponseErrorHandler
    // 它能够利用消息换换气提取你的错误内容。并且还支持自定义错误码、错误序列等等~
    private ResponseErrorHandler errorHandler = new DefaultResponseErrorHandler();
    // 用于URL的构建
    private UriTemplateHandler uriTemplateHandler;
    // 默认的返回值提取器~~~~
    private final ResponseExtractor<HttpHeaders> headersExtractor = new HeadersExtractor();

    // 空构造,应该是平时使用得最多的了:一切都使用默认的组件配置Resource等等
    public RestTemplate() {
        // 这个几个消息转换器是支持的。字节数组、字符串、
        this.messageConverters.add(new ByteArrayHttpMessageConverter());
        this.messageConverters.add(new StringHttpMessageConverter());
        this.messageConverters.add(new ResourceHttpMessageConverter(false));
        this.messageConverters.add(new SourceHttpMessageConverter<>());
        // 对form表单提交方式的支持
        this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());

        // 接下里便是一些列的判断,若类路径上有才会加进来
        if (jackson2Present) {
            this.messageConverters.add(new MappingJackson2HttpMessageConverter());
        }
        ...
        // new DefaultUriBuilderFactory()
        this.uriTemplateHandler = initUriTemplateHandler();
    }

    // 你懂的,若想用OkHttp,也可以在构造时就指定
    public RestTemplate(ClientHttpRequestFactory requestFactory) {
        this();
        setRequestFactory(requestFactory);
    }

    // 若不想用默认的消息转换器,也可以自己指定(其实一般都不这么去干,而是后面自己再add进来)
    public RestTemplate(List<HttpMessageConverter<?>> messageConverters) {
        Assert.notEmpty(messageConverters, "At least one HttpMessageConverter required");
        this.messageConverters.addAll(messageConverters);
        this.uriTemplateHandler = initUriTemplateHandler();
    }
    ... // 省略上面属性的get/set犯法们
}

这部分源码我列出来,都是在对构建一个RestTemplate实例的准备工作相关方法,包括对各个相关组件的设置。

接下来更重要的便是它实现的接口方法了,我抽出一些关键点进行描述说明:

RestTemplate:

    @Override
    @Nullable
    public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {
        //1、new AcceptHeaderRequestCallback(responseType)  它能在发送请求的之前这样一件事:
        // request.getHeaders().setAccept(allSupportedMediaTypes)
        RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
        HttpMessageConverterExtractor<T> responseExtractor = new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);

        // 最终调用的是execute方法,此时URL是个字符串
        // responseExtractor返回值提取器使用的是消息转换器去读取body哒~
        // 返回值就是返回的body本身(不含有返回的响应头等等信息~)
        return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
    }

    // 它返回的是ResponseEntity,不会返回null的  最终调用的依旧是execute方法
    // 此时候用的就不是消息转换器的提取器了,而是内部类`ResponseEntityResponseExtractor`(底层还是依赖消息转换器)
    // 但是这个提取器,提取出来的可都是ResponseEntity<T>实例~
    @Override
    public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {
        RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
        ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
        return nonNull(execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));
    }

    // HEAD请求:很简单,使用的提取器就是headersExtractor,从返回值里把响应header拿出来即可
    @Override
    public HttpHeaders headForHeaders(String url, Object... uriVariables) throws RestClientException {
        return nonNull(execute(url, HttpMethod.HEAD, null, headersExtractor(), uriVariables));
    }

    // POST请求
    @Override
    @Nullable
    public URI postForLocation(String url, @Nullable Object request, Object... uriVariables) throws RestClientException {
        // 1、HttpEntityRequestCallback  适配:把request适配成一个HttpEntity
        // 然后执行前,通过消息转换器把头信息、body信息等等都write进去
        RequestCallback requestCallback = httpEntityCallback(request);
        // 因为需要拿到URI,所以此处使用headersExtractor提取器先拿到响应的header即可~~~
        HttpHeaders headers = execute(url, HttpMethod.POST, requestCallback, headersExtractor(), uriVariables);
        return (headers != null ? headers.getLocation() : null);
    }

    // 除了httpEntityCallback()不一样,其余和get请求一样
    @Override
    @Nullable
    public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) throws RestClientException {
        RequestCallback requestCallback = httpEntityCallback(request, responseType);
        HttpMessageConverterExtractor<T> responseExtractor =
                new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
        return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
    }

    // PUT请求:因为没有返回值,所以不需要返回值提取器。所以,非常的简单~~~
    @Override
    public void put(String url, @Nullable Object request, Object... uriVariables) throws RestClientException {
        RequestCallback requestCallback = httpEntityCallback(request);
        execute(url, HttpMethod.PUT, requestCallback, null, uriVariables);
    }

    // DELETE请求:也是木有返回值的。
    // 并且请注意:DELETE请求这里可都是不能接收body的,不能给请求设置请求体的
    // (虽然可能底层httpCLient支持,但这里不支持,请遵守规范)
    @Override
    public void delete(String url, Object... uriVariables) throws RestClientException {
        execute(url, HttpMethod.DELETE, null, null, uriVariables);
    }

    // OPTIONS请求:和HEAD请求的处理逻辑几乎一样
    @Override
    public Set<HttpMethod> optionsForAllow(String url, Object... uriVariables) throws RestClientException {
        ResponseExtractor<HttpHeaders> headersExtractor = headersExtractor();
        HttpHeaders headers = execute(url, HttpMethod.OPTIONS, null, headersExtractor, uriVariables);
        return (headers != null ? headers.getAllow() : Collections.emptySet());
    }

所有方法大体执行逻辑一致,都是和RequestCallbackresponseExtractor等有关,且最终都是委托给了最为底层的execute()方法去执行。

你是否疑问:它提供的put方法返回值都是void,若我put请求就有返回值肿么办呢?那么接下来就介绍更为通用的一个方法:exchange()

RestTemplate:

    @Override
    public <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
        // 把请求体适配为HttpEntity
        RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
        // 消息提取器使用ResponseEntityResponseExtractor
        ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);

        // 从上两个部分就能看到:exchange方法的入参、出参都是非常通用的~~~
        return nonNull(execute(url, method, requestCallback, responseExtractor, uriVariables));
    }

    // ParameterizedTypeReference参数化类型,用于处理泛型
    // 上面的responseType就是个Class。这里是个参数化类型~~~~~
    @Override
    public <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType, Object... uriVariables) throws RestClientException {

        Type type = responseType.getType();
        RequestCallback requestCallback = httpEntityCallback(requestEntity, type);
        ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(type);
        return nonNull(execute(url, method, requestCallback, responseExtractor, uriVariables));
    }

    // 这个方法就非常精简了,让调用者自己去构造RequestEntity,里面是包含了请求的URL和方法等信息的
    @Override
    public <T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, Class<T> responseType) throws RestClientException {
        RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
        ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
        return nonNull(doExecute(requestEntity.getUrl(), requestEntity.getMethod(), requestCallback, responseExtractor));
    }

exchange所有方法使用的都是HttpEntityResponseEntity代表请求实体和响应实体,足以见到它设计的通用性。

在Spring3.2后提供了ParameterizedTypeReference来处理参数化类型---> 主要是为了处理List等的泛型

可以发现即使是exchange()方法,最终还是委托给execute/doExecute去执行的:

RestTemplate:

    // 3个execute方法。最终调用的都是doExecute方法
    // 它做的一件事:使用UriTemplateHandler把URL的参数填进去~~~
    // 底层使用的是我上文介绍的`UriComponentsBuilder`,还是比较简单的
    @Override
    @Nullable
    public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException {
        URI expanded = getUriTemplateHandler().expand(url, uriVariables);
        return doExecute(expanded, method, requestCallback, responseExtractor);
    }

doExecute方法:
    @Nullable
    protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
        ClientHttpResponse response = null;
        ClientHttpRequest request = createRequest(url, method);
        // 如果有回调,那就先回调处理一下子请求
        if (requestCallback != null) {
            requestCallback.doWithRequest(request);
        }
        // 真正意义上的发送请求。
        // 请注意:如果这里的request是`InterceptingClientHttpRequest`,那就回执行拦截器的intercept方法哦~~~
        // 至于什么时候是InterceptingClientHttpRequest呢?这个上面有讲的
        response = request.execute();
        // 处理结果(若有错误,那就抛出异常~~~)
        handleResponse(url, method, response);

        // 请求正常。那就使用返回值提取器responseExtractor提取出内容即可了~~~
        return (responseExtractor != null ? responseExtractor.extractData(response) : null);
        ...
        // 关闭响应(ClientHttpResponse继承了Closeable接口)
        finally {
            if (response != null) {
                response.close();
            }
        }
    }

看完doExecute()的模板式的实现步骤,就清楚了RestTemplate从发出一个请求到收到一个响应的完整过程。Spring设计了多个相关组件,提供钩子程序让我们可以干预到流程里面去,最常见的当然就是请求拦截器了,它在Ribbon负载均衡和Hystrix熔断器里面有很好的应用~

AsyncRestTemplate

它是@since 4.0新增的用于解决一些异步Http请求的场景,但它寿命比较短,在Spring5.0就标记为@Deprecated,而被推荐使用WebClient去代替它。

它的实现基础原理是:RestTemplate + SimpleAsyncTaskExecutor任务池的方式去实现的异步请求,返回值均为ListenableFuture。掌握了RestTemplate后,它使用起来是没有什么障碍的

极简使用Demo Show

看过了原理的描述,我有理由相信你已经烂熟于胸并对RestTemplate能够运用自如了。因此关于使用方面,本文只给如下非常简单的一个Demo Show我认为是够了的:

public static void main(String[] args) throws IOException {
    RestTemplate restTemplate = new RestTemplate();
    String pageHtml = restTemplate.getForObject("http://www.baidu.com", String.class);
    System.out.println(pageHtml); // 百度首页的html...
}

解释一点:这里请求得到的是一个html网页,所以HttpMessageConverterExtractor去提取响应时,使用的是StringHttpMessageConverter去处理的,提取代码如下:

StringHttpMessageConverter:
    @Override
    protected String readInternal(Class<? extends String> clazz, HttpInputMessage inputMessage) throws IOException {
        // 从响应头的contentType里提取(若是application/json,那默认也是urf-8)
        // 若没有指定编码,就取值getDefaultCharset。比如本处访问百度,就取值默认值`ISO-8859-1`对body体进行编码的~
        Charset charset = getContentTypeCharset(inputMessage.getHeaders().getContentType());
        return StreamUtils.copyToString(inputMessage.getBody(), charset);
    }

小伙伴把此请求案例可以和上面我使用ClientHttpRequestFactory发送请求的案例对比(或者和你自己使用HttpClient步骤对比),感受感受使用RestTemplate是多么的优雅~

推荐阅读

RestTemplate组件:ClientHttpRequestFactory、ClientHttpRequestInterceptor、ResponseExtractor【享学Spring MVC】
为何一个@LoadBalanced注解就能让RestTemplate拥有负载均衡的能力?【享学Spring Cloud】

总结

微服务作为主流的今天,RestTemplate可谓是一把利器,每个程序员都应该掌握它。深入理解它对实际应用、调优都有很现实的意义,所以我相信本文能够帮助到你,做到烂熟于胸。
预告一下:下篇文章会原理分析告诉大家为何一个简单的@LoadBalanced注解就能让RestTemplate拥有负载均衡的能力?

== 若对Spring、SpringBoot、MyBatis等源码分析感兴趣,可加我wx:fsx641385712,手动邀请你入群一起飞 ==
== 若对Spring、SpringBoot、MyBatis等源码分析感兴趣,可加我wx:fsx641385712,手动邀请你入群一起飞 ==

原文地址:https://www.cnblogs.com/fangshixiang/p/11532755.html

时间: 2024-07-31 18:19:24

RestTemplate的使用和原理你都烂熟于胸了吗?【享学Spring MVC】的相关文章

RestTemplate相关组件:ClientHttpRequestInterceptor【享学Spring MVC】

每篇一句 做事的人和做梦的人最大的区别就是行动力 前言 本文为深入了解Spring提供的Rest调用客户端RestTemplate开山,对它相关的一些组件做讲解. Tips:请注意区分RestTemplate和RedisTemplate哦~ ClientHttpRequestFactory 它是个函数式接口,用于根据URI和HttpMethod创建出一个ClientHttpRequest来发送请求~ ClientHttpRequest它代表请求的客户端,该接口继承自HttpRequest.Htt

为何一个@LoadBalanced注解就能让RestTemplate拥有负载均衡的能力?【享学Spring Cloud】

每篇一句 你应该思考:为什么往往完成比完美更重要? 前言 在Spring Cloud微服务应用体系中,远程调用都应负载均衡.我们在使用RestTemplate作为远程调用客户端的时候,开启负载均衡极其简单:一个@LoadBalanced注解就搞定了. 相信大家大都使用过Ribbon做Client端的负载均衡,也许你有和我一样的感受:Ribbon虽强大但不是特别的好用.我研究了一番,其实根源还是我们对它内部的原理不够了解,导致对一些现象无法给出合理解释,同时也影响了我们对它的定制和扩展.本文就针对

从原理层面掌握HandlerMethod、InvocableHandlerMethod、ServletInvocableHandlerMethod的使用【一起学Spring MVC】

每篇一句 想当火影的人没有近道可寻,当上火影的人同样无路可退 前言 HandlerMethod它作为Spring MVC的非公开API,可能绝大多数小伙伴都对它比较陌生,但我相信你对它又不是那么的生疏,因为你可能没用过但肯定见过. 比如Spring MVC的拦截器HandlerInterceptor的拦截方法的第三个入参Object handler,虽然它是Object类型,但其实绝大部分情况下我们都会当作HandlerMethod来使用:又比如我之前的这篇讲RequestMappingHand

【Spring】Spring MVC原理及配置详解

1.Spring MVC概述: Spring MVC是Spring提供的一个强大而灵活的web框架.借助于注解,Spring MVC提供了几乎是POJO的开发模式,使得控制器的开发和测试更加简单.这些控制器一般不直接处理请求,而是将其委托给Spring上下文中的其他bean,通过Spring的依赖注入功能,这些bean被注入到控制器中. Spring MVC主要由DispatcherServlet.处理器映射.处理器(控制器).视图解析器.视图组成.他的两个核心是两个核心: 处理器映射:选择使用

spring Mvc 执行原理 及 xml注解配置说明 (六)

Spring MVC 执行原理 在 Spring Mvc 访问过程里,每个请求都首先经过 许多的过滤器,经 DispatcherServlet 处理; 一个Spring MVC工程里,可以配置多个的 dispatcherServlet ,每个 DispatcherServlet 可以对应多个的 HandlerMapping ,每个 HandlerMapping 可以有自己的 Interceptor (拦截器). 1. 请求首先 由 前端 DispatcherServlet 捕获: 2. Disp

spring mvc控制框架的流程及原理1: 总概及源码分析

主要介绍spring mvc控制框架的流程及原理 Spring Web MVC处理请求的流程 具体执行步骤如下: 首先用户发送请求————>前端控制器,前端控制器根据请求信息(如URL)来决定选择哪一个页面控制器进行处理并把请求委托给它,即以前的控制器的控制逻辑部分:图2-1中的1.2步骤: 页面控制器接收到请求后,进行功能处理,首先需要收集和绑定请求参数到一个对象,这个对象在Spring Web MVC中叫命令对象,并进行验证,然后将命令对象委托给业务对象进行处理:处理完毕后返回一个Model

spring mvc 工作原理

SpringMVC框架介绍 1) Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面. Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块.使用 Spring 可插入的 MVC 架构,可以选择是使用内置的 Spring Web 框架还是 Struts 这样的 Web 框架.通过策略接口,Spring 框架是高度可配置的,而且包含多种视图技术,例如 JavaServer Pages(JSP)技术.Velocity.Til

【转】spring Mvc 执行原理 及 xml注解配置说明

Spring MVC 执行原理 在 Spring Mvc 访问过程里,每个请求都首先经过 许多的过滤器,经 DispatcherServlet 处理; 一个Spring MVC工程里,可以配置多个的 dispatcherServlet ,每个 DispatcherServlet 可以对应多个的 HandlerMapping ,每个 HandlerMapping 可以有自己的 Interceptor (拦截器). 1. 请求首先 由 前端 DispatcherServlet 捕获: 2. Disp

spring mvc的工作原理

该文转载自:http://blog.csdn.net/u012191627/article/details/41943393 SpringMVC框架介绍 1) spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面. Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块.使用 Spring 可插入的 MVC 架构,可以选择是使用内置的 Spring Web 框架还是 Struts 这样的 Web 框架.通过策略接口,Spri