Недавно я использовал класс RestTemplate и потратил некоторое время, чтобы обобщить некоторые вещи, надеясь помочь всем.
Начиная с версии 3.0, Spring предоставляет RestTemplate в качестве клиента для доступа к службам Rest.RestTemplate предоставляет множество удобных методов для доступа к удаленным службам Http, которые могут значительно повысить эффективность написания клиентов.
Эта статья начнется с API, предоставляемого RestTemplate, сначала для понимания конкретного использования RestTemplate, а затем проанализирует несколько задействованных основных классов и, наконец, проанализирует весь процесс выполнения RestTemplate, длина относительно длинная, рекомендуется сначала Код быстрый!
Основной API
При обычном использовании мы обычно используем упакованные getForObject/getForEntity, postForObject/postForEntity/postForLocation, помещаем и удаляем.
получить обработку запроса
Возвращаемое значение метода getForEntity — это ResponseEntity, который представляет собой инкапсуляцию Spring ответа на HTTP-запрос, включая несколько важных элементов, таких как код ответа, contentType, contentLength и тело ответного сообщения.
- url: адрес вызываемой службы
- responseType: возвращаемый тип тела
- uriVariables: есть две формы:
- Вы можете использовать число в качестве заполнителя и, наконец, параметр переменной длины, чтобы заменить предыдущие заполнители один за другим.
- Вы также можете использовать форму name={name}.Последний параметр — это карта, ключ карты — это имя предыдущего заполнителя, а значение карты — это значение параметра.
Тестовый пример типа ответа
Определенный ресурс контроллера:
Здесь тестируются разные типы ответов:результат:
getForEntity(responseType=Map.class):{glmapper=hello glmapper}
getForEntity(responseType=String.class):{"glmapper":"hello glmapper"}
тестовый пример uriVariables
Давайте сначала рассмотрим метод без карты, два контроллера, два разных метода получения параметров (по сути одинаковые)
- Способы использования заполнителей:
- Как использовать карту:
getForObject
Функция getForObject на самом деле является дальнейшей инкапсуляцией функции getForEntity.Если вы обращаете внимание только на содержимое тела возвращаемого сообщения и не заботитесь о другой информации, вы можете использовать getForObject.
Вызов здесь немного проще, чем getForEntity, вы можете получить объект напрямую:
Несколько перегруженных методов getForObject в основном такие же, как и у getForEntity.
обработка пост-запроса
В RestTemplate запросы POST можно инициировать с помощью следующих трех методов: postForEntity, postForObject, postForLocation.
Случай postForEntity
Звоните, чтобы получить:postForEntity(URI url, @Nullable Object request, Class<T> responseType)
- Первый параметр метода представляет собой адрес вызываемой службы.
- Второй параметр метода представляет загруженные параметры
- Третий параметр метода указывает тип данных возвращаемого тела сообщения.
случай postForObject
В соответствии с getForObject, он обращает внимание только на возвращаемое тело сообщения.
Случай postForLocation
postForLocation также отправляет новый ресурс. После успешной отправки возвращается URI нового ресурса. Параметры postForLocation в основном такие же, как и два предыдущих параметра, но возвращаемое значение этого метода — Uri, для которого требуется только поставщик услуг, чтобы вернуть Uri.Этот Uri представляет расположение нового ресурса.
Здесь есть небольшая яма, нам нужно добавить этот uri в заголовок ответа, иначе мы получим null позже.
exchange
Отличие метода exchange от вышеописанных методов в том, что он требует еще один параметр типа запроса:
Асинхронный клиент AsyncRestTemplate
Асинхронная реализация RestTemplate. Используемый API в основном такой же, как RestTemplate. Разница в том, что RestTemplate возвращает результат напрямую, а AsyncRestTemplate возвращает ListenableFuture.
Перехватчик RestTemplate
Spring предоставляет два интерфейса, ClientHttpRequestInterceptor и AsyncClientHttpRequestInterceptor, которые могут перехватывать запросы, инициированные RestTemplate и AsyncRestTemplate соответственно, и изменять запрос или улучшать соответствующую информацию перед ее отправкой на сервер.
-
ClientHttpRequestInterceptor перехватывает RestTemplate
-
AsyncClientHttpRequestInterceptor перехватывает AsyncRestTemplate
Чтобы установить перехватчик, вы можете установить его через предоставленный setInterceptors:
Пользовательский ResponseErrorHandler
Интерфейс ResponseErrorHandler определяет, что делать, если в ответе возникает ошибка. Здесь мы настраиваем CustomResponseErrorHandler, когда возвращаемый код не равен 200, это означает, что выполнение пошло не так.
Установите ResponseErrorHandler:
Результаты:
Технологический поток
Разберем процесс обработки запроса в RestTemplate. На рисунке ниже XXXX представляет метод API, который мы вызываем. Общий процесс таков: выполните некоторую инкапсуляцию обработки запросов внутри API, затем передайте ее методу execute для выполнения, и, наконец, реальная обработка выполняется в методе doExecute.
Ниже приведен анализ процесса выполнения метода getForEntity:
Метод getForEntity:
- На основе заданного типа ответа возвращает реализацию обратного вызова запроса, которая подготавливает запрос.
- Средство извлечения ответов, которое возвращает ResponseEntity на основе заданного типа ответа.
- В этом методе URL-адрес обрабатывается кодировкой urlencode и единообразно преобразуется в URL-адрес. Здесь мы также можем вручную закодировать параметры в сети.
- createRequest
- doWithRequest
- execute
- handleResponse
1. создать запрос
Цель этого метода — создать объект ClientHttpRequest. RestTemplate интегрирует абстрактный класс HttpAccessor.Процесс создания ClientHttpRequest заключается в завершении создания конкретного запроса с помощью класса реализации ClientHttpRequestFactory по умолчанию SimpleClientHttpRequestFactory в его родительском классе HttpAccessor.
-
1. Создайте объект java.net.HttpURLConnection.
-
2. Установите соединение, включая connectTimeout, setDoInput и т. д.
-
3. bufferRequestBody используется, чтобы указать, следует ли использовать форму кэшированного потока, значение по умолчанию — true. Недостаток в том, что при отправке большого количества данных, таких как put/post, происходит серьезное потребление памяти. Это значение может быть изменено SimpleClientHttpRequestFactory#setBufferRequestBody.
Изменения в разных версиях все еще относительно велики, когда вы читаете исходный код, вы все еще смотрите на последний код.
2. сделать с запросом
RequestCallback инкапсулирует тело запроса и объекты заголовка запроса. Здесь все HttpMessageConverters будут пройдены, проанализированы на все поддерживаемые MediaTypes и помещены в allSupportedMediaTypes.
request.getHeaders().setAccept(allSupportedMediaTypes);
RestTemplate соответствует реализации двух внутренних классов:
-
Обработка AcceptHeaderRequestCallback.doWithRequest. При отправке запроса в заголовке Http необходимо установить поле Accept, в котором указывается тип носителя (формат сообщения), принятый стороной, отправляющей запрос, а также тип носителя (формат сообщения) информации, которая должна быть возвращена ответчиком. . По третьему параметру responseType метода postForEntity программа выберет соответствующий парсер XXXConverter и найдет все поддерживаемые типы мультимедиа в соответствии с парсером.
-
Обработка HttpEntityRequestCallback.doWithRequest. Если это запрос POST и тело сообщения существует, в дополнение к установке поля Accept вам также может потребоваться установить поле Content-Type, которое указывает тип носителя (формат сообщения) отправленного запроса и тип носителя ( формат сообщения), принятый ответчиком. По второму параметру запроса метода postForEntity программа выберет соответствующий парсер XXXConverter и запишет сообщение запроса в выходной поток.
3. выполнить
Здесь заголовок/тело запроса будет инкапсулировано в соединение, после чего запрос будет отправлен. Отследите выполнение метода execute и найдите метод SimpleBufferingClientHttpRequest#executeInternal:
Вот пример SimpleBufferingClientHttpRequest для инкапсуляции тела запроса и заголовков запроса. Как видно из кода:- При удалении определяется нужно ли отправлять тело запроса установленным ранее параметром DoOutput и можно ли задать поток вывода.Если это запрос на удаление, то очевидно DoOutput=false, не будет процесса инкапсуляции тело запроса, то есть FileCopyUtils.copy(bufferedOutput не выполняется. , this.connection.getOutputStream()).
4. обработать ответ
Последняя часть — разбор ответа, с точки зрения кода — это в основном разбор ошибки. ErrorHandler здесь также упоминался ранее, а обработка исключений может быть настроена путем реализации ResponseErrorHandler.
резюме
В этой статье сначала рассказывается об использовании RestTemplate API, выбирается несколько и рассказывается о них.Для различных сценариев необходимо определить дополнительные детали использования. Затем кратко рассказывается о перехватчике, асинхронном RestTemplate и обработчике ошибок, а также приводятся примеры. Наконец, анализируется процесс выполнения RestTemplate. Часть процесса выполнения является лишь грубым наброском из-за недостатка места. Есть еще много деталей, которые нужно добавить со временем. Эта часть в основном зависит от того, как взаимодействует нижний уровень, передача параметры, которые были запрошены, и так далее.