com.github.lianjiatech.retrofit.spring.boot.core.BasicTypeConverterFactory
Глобальные настройки адаптера вызова
global-call-adapter-factories:
Настройки глобального журнала
global-log:
Глобальная конфигурация повторов
global-retry:
Конфигурация глобального тайм-аута
global-timeout:
Настройка деградации и понижения уровня обслуживания
degrade:
Автоматическая установка области действия PathMathInterceptor на prototype
auto-set-prototype-scope-for-path-math-interceptor: true
Если вам нужно изменить только время ожидания OkHttpClient, вы можете сделать это с помощью соответствующих полей @RetrofitClient или глобальной конфигурации.
Чтобы настроить другие параметры OkHttpClient, можно создать собственный OkHttpClient. Вот как это делается:
@Component
public class CustomOkHttpClientRegistrar implements SourceOkHttpClientRegistrar {
@Override
public void register(SourceOkHttpClientRegistry registry) {
// Регистрация customOkHttpClient с временем ожидания 1 секунда
registry.register("customOkHttpClient", new OkHttpClient.Builder()
.connectTimeout(Duration.ofSeconds(1))
.writeTimeout(Duration.ofSeconds(1))
.readTimeout(Duration.ofSeconds(1))
.addInterceptor(chain -> chain.proceed(chain.request()))
.build());
}
}
@RetrofitClient(baseUrl = "${test.baseUrl}", sourceOkHttpClient = "customOkHttpClient")
public interface CustomOkHttpUserService {
/**
* Получение информации о пользователе по id
*/
@GET("getUser")
User getUser(@Query("id") Long id);
}
Обратите внимание: компоненты не используют указанный OkHttpClient напрямую, а создают на его основе новый.
Компоненты предоставляют аннотированные перехватчики, которые поддерживают сопоставление путей URL. Для их использования выполните следующие шаги:
Если вам нужно использовать несколько перехватчиков, просто добавьте несколько аннотаций @Intercept к интерфейсу.
@Component
public class PathMatchInterceptor extends BasePathMatchInterceptor {
@Override
protected Response doIntercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
// Добавляем заголовок path.match в ответ
return response.newBuilder().header("path.match", "true").build();
}
}
По умолчанию компонент автоматически устанавливает область действия BasePathMatchInterceptor как prototype. Вы можете отключить эту функцию, установив retrofit.auto-set-prototype-scope-for-path-math-interceptor=false. После отключения вам необходимо вручную установить область действия на prototype.
@Component
@Scope("prototype")
public class PathMatchInterceptor extends BasePathMatchInterceptor {
}
@RetrofitClient(baseUrl = "${test.baseUrl}")
@Intercept(handler = PathMatchInterceptor.class, include = {"/api/user/**"}, exclude = "/api/user/getUser")
// @Intercept() Если вам нужно использовать несколько путей сопоставления перехватчиков, продолжайте добавлять @Intercept.
public interface InterceptorUserService {
/**
* Получение имени пользователя по id
*/
@POST("getName")
Response<String> getName(@Query("id") Long id);
/**
* Получение информации о пользователе по id
*/
@GET("getUser")
Response<User> getUser(@Query("id") Long id);
} **Вот перевод текста на русский язык:**
«Конфигурация `@Intercept` выше означает: перехватывать запросы, которые соответствуют пути `/api/user/**`, за исключением `/api/user/getUser`, и обрабатывать их с помощью `PathMatchInterceptor`».
### Создание пользовательских перехватчиков
Иногда нам нужно динамически передавать некоторые параметры в «перехватчик» и использовать эти параметры при перехвате. В этом случае мы можем создать «пользовательский перехватчик», выполнив следующие шаги:
1. Создать аннотацию. Она должна быть помечена как `@InterceptMark`, а также содержать поля `include`, `exclude` и `handler`.
2. Наследовать от `BasePathMatchInterceptor`, чтобы написать обработчик для перехватчика.
3. Использовать пользовательскую аннотацию в интерфейсе.
Например, если нам нужно добавить информацию о подписи в заголовке запроса (accessKeyId и accessKeySecret), чтобы отправить HTTP-запрос, мы можем использовать пользовательскую аннотацию `@Sign` для реализации этой функции.
#### Пользовательская аннотация `@Sign`
```java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@InterceptMark
public @interface Sign {
String accessKeyId();
String accessKeySecret();
String[] include() default {"/**"};
String[] exclude() default {};
Class<? extends BasePathMatchInterceptor> handler() default SignInterceptor.class;
}
В аннотации @Sign
указано, что обработчиком является SignInterceptor
.
SignInterceptor
@Component
@Setter
public class SignInterceptor extends BasePathMatchInterceptor {
private String accessKeyId;
private String accessKeySecret;
@Override
public Response doIntercept(Chain chain) throws IOException {
Request request = chain.request();
Request newReq = request.newBuilder()
.addHeader("accessKeyId", accessKeyId)
.addHeader("accessKeySecret", accessKeySecret)
.build();
Response response = chain.proceed(newReq);
return response.newBuilder().addHeader("accessKeyId", accessKeyId)
.addHeader("accessKeySecret", accessKeySecret).build();
}
}
Обратите внимание: поля
accessKeyId
иaccessKeySecret
должны иметь методsetter
.
Значения полей accessKeyId
и accessKeySecret
перехватчика будут автоматически введены на основе значений accessKeyId()
и accessKeySecret()
в аннотации @Sign
. Если в аннотации указаны заполнители, то будут использоваться значения из конфигурации.
@Sign
в интерфейсах@RetrofitClient(baseUrl = "${test.baseUrl}")
@Sign(accessKeyId = "${test.accessKeyId}", accessKeySecret = "${test.accessKeySecret}", include = "/api/user/getAll")
public interface InterceptorUserService {
/**
* Запрос всех пользовательских данных
*/
@GET("getAll")
Response<List<User>> getAll();
}
Компонент поддерживает глобальное ведение журнала и декларативное ведение журнала.
По умолчанию глобальное ведение журнала включено, и его конфигурация выглядит следующим образом:
retrofit:
# Конфигурация глобального ведения журнала
global-log:
# Включить ведение журнала
enable: true
# Уровень глобального ведения журнала
log-level: info
# Стратегия глобального ведения журнала
log-strategy: basic
# Агрегировать ли журналы запросов
aggregate: true
# Имя журнала, по умолчанию — полное имя класса {@link LoggingInterceptor}
logName: com.github.lianjiatech.retrofit.spring.boot.log.LoggingInterceptor
Существует четыре стратегии ведения журнала:
NONE
: не вести журнал.BASIC
: регистрировать строки запросов и ответов.HEADERS
: регистрировать строки запросов, ответов и соответствующие заголовки.BODY
: регистрировать строки запросов, ответов, соответствующие заголовки и тела (если есть).Если необходимо регистрировать только часть запросов, можно использовать аннотацию @Logging
в соответствующем интерфейсе или методе.
Для изменения поведения ведения журнала можно наследовать класс LoggingInterceptor
и настроить его как Spring bean
.
Компонент поддерживает глобальные повторные попытки и декларативные повторные попытки.
Глобальные повторные попытки по умолчанию отключены, а конфигурация выглядит следующим образом:
retrofit:
# Конфигурация глобальных повторных попыток
global-retry:
# Включить ли глобальные повторные попытки
enable: false
# Интервал времени между повторными попытками в миллисекундах
interval-ms: 100
# Максимальное количество повторных попыток
max-retries: 2
# Правила повторных попыток
retry-rules:
- response_status_not_2xx
- occur_io_exception
Правила повторных попыток могут быть настроены тремя способами:
RESPONSE_STATUS_NOT_2XX
: повторить попытку, если статус ответа не равен 2xx
.OCCUR_IO_EXCEPTION
: повторить попытку при возникновении исключения ввода-вывода.OCCUR_EXCEPTION
: повторить попытку при любом исключении.Если только часть запросов требует повторной попытки, можно использовать аннотацию @Retry
в соответствующем интерфейсе или методе.
Чтобы изменить поведение повторных попыток, можно наследовать RetryInterceptor
и настроить его как Spring bean
.
Отключение и понижение уровня обслуживания по умолчанию отключено, и в настоящее время поддерживаются две реализации: sentinel
и resilience4j
.
retrofit:
# Конфигурация отключения и понижения уровня обслуживания
degrade:
# Тип отключения и понижения уровня обслуживания. По умолчанию none, что означает, что отключение и понижение уровня обслуживания не включены
degrade-type: sentinel
Включите degrade-type=sentinel
, затем объявите аннотацию @SentinelDegrade
в соответствующем интерфейсе или методе, чтобы активировать Sentinel.
Не забудьте вручную импортировать зависимость Sentinel
:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.6.3</version>
</dependency>
Кроме того, поддерживается глобальная конфигурация Sentinel для отключения и понижения уровня обслуживания:
retrofit:
# Конфигурация отключения и понижения уровня обслуживания
degrade:
# Тип отключения и понижения уровня обслуживания. По умолчанию none, что означает, что отключение и понижение уровня обслуживания не включены
degrade-type: sentinel
# Глобальная конфигурация Sentinel для отключения и понижения уровня обслуживания
global-sentinel-degrade:
# Включить ли
enable: true
# ...другие глобальные конфигурации Sentinel
Примечание: в тексте запроса присутствуют фрагменты кода на языке Java, но они не были переведены, так как не являются частью основного текста. Конфигурация: degrade-type=resilience4j. Затем в соответствующем интерфейсе или методе объявите @Resilience4jDegrade.
Не забудьте вручную импортировать Resilience4j:
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-circuitbreaker</artifactId>
<version>1.7.1</version>
</dependency>
Через следующую конфигурацию можно включить глобальный resilience4j деградацию:
retrofit:
# 熔断降级配置
degrade:
# 熔断降级类型。默认none,表示不启用熔断降级
degrade-type: resilience4j
# 全局resilience4j降级配置
global-resilience4j-degrade:
# 是否开启
enable: true
# 根据该名称从#{@link CircuitBreakerConfigRegistry}获取CircuitBreakerConfig,作为全局熔断配置
circuit-breaker-config-name: defaultCircuitBreakerConfig
Управление конфигурацией деградации:
Реализуйте интерфейс CircuitBreakerConfigRegistrar и зарегистрируйте CircuitBreakerConfig.
@Component
public class CustomCircuitBreakerConfigRegistrar implements CircuitBreakerConfigRegistrar {
@Override
public void register(CircuitBreakerConfigRegistry registry) {
// 替换默认的CircuitBreakerConfig
registry.register(Constants.DEFAULT_CIRCUIT_BREAKER_CONFIG, CircuitBreakerConfig.ofDefaults());
// 注册其它的CircuitBreakerConfig
registry.register("testCircuitBreakerConfig", CircuitBreakerConfig.custom()
.slidingWindowType(CircuitBreakerConfig.SlidingWindowType.TIME_BASED)
.failureRateThreshold(20)
.minimumNumberOfCalls(5)
.permittedNumberOfCallsInHalfOpenState(5)
.build());
}
}
С помощью circuitBreakerConfigName укажите CircuitBreakerConfig. Включая retrofit.degrade.global-resilience4j-degrade.circuit-breaker-config-name или @Resilience4jDegrade.circuitBreakerConfigName.
Расширение деградации и понижения:
Если пользователю необходимо использовать другую реализацию деградации и понижения, наследуйте BaseRetrofitDegrade и сделайте его конфигурацией Spring Bean.
Настройка fallback или fallbackFactory (необязательно):
Если @RetrofitClient не устанавливает fallback или fallbackFactory, при срабатывании деградации будет непосредственно выброшено исключение RetrofitBlockException. Пользователи могут настроить возвращаемое значение метода при деградации, установив fallback или fallbackFactory.
Обратите внимание: класс fallback должен быть реализацией текущего интерфейса, а класс fallbackFactory должен быть реализацией FallbackFactory, где T является универсальным параметром типа текущего интерфейса. Кроме того, экземпляры fallback и fallbackFactory должны быть настроены как Spring Bean.
Основное отличие fallbackFactory от fallback заключается в том, что он может воспринимать причину каждого сбоя деградации (cause).
Пример:
@Slf4j
@Service
public class HttpDegradeFallback implements HttpDegradeApi {
@Override
public Result<Integer> test() {
Result<Integer> fallback = new Result<>();
fallback.setCode(100)
.setMsg("fallback")
.setBody(1000000);
return fallback;
}
}
@Slf4j
@Service
public class HttpDegradeFallbackFactory implements FallbackFactory<HttpDegradeApi> {
@Override
public HttpDegradeApi create(Throwable cause) {
log.error("触发熔断了! ", cause.getMessage(), cause);
return new HttpDegradeApi() {
@Override
public Result<Integer> test() {
Result<Integer> fallback = new Result<>();
fallback.setCode(100)
.setMsg("fallback")
.setBody(1000000);
return fallback;
}
};
}
}
Когда происходит ошибка запроса HTTP (включая возникновение исключения или данные ответа не соответствуют ожиданиям), декодер ошибок может декодировать информацию HTTP в пользовательское исключение. Вы можете указать текущий декодер ошибок интерфейса в аннотации @RetrofitClient errorDecoder(). Пользовательский декодер ошибок должен реализовать интерфейс ErrorDecoder.
Пользователи могут самостоятельно реализовать интерфейс ServiceInstanceChooser для завершения логики выбора экземпляра службы и настроить его как Spring Bean. Для приложений Spring Cloud можно использовать следующую реализацию.
@Service
public class SpringCloudServiceInstanceChooser implements ServiceInstanceChooser {
private LoadBalancerClient loadBalancerClient;
@Autowired
public SpringCloudServiceInstanceChooser(LoadBalancerClient loadBalancerClient) {
this.loadBalancerClient = loadBalancerClient;
}
/**
* Chooses a ServiceInstance URI from the LoadBalancer for the specified service.
*
* @param serviceId The service ID to look up the LoadBalancer.
* @return Return the uri of ServiceInstance
*/
@Override
public URI choose(String serviceId) {
ServiceInstance serviceInstance = loadBalancerClient.choose(serviceId);
Assert.notNull(serviceInstance, "can not found service instance! serviceId=" + serviceId);
return serviceInstance.getUri();
``` #### 指定 `serviceId` и `path`
```java
@RetrofitClient(serviceId = "user", path = "/api/user")
public interface ChooserOkHttpUserService {
/**
* 根据 id 查询用户信息
*/
@GET("getUser")
User getUser(@Query("id") Long id);
}
Если нам нужно выполнить унифицированную обработку перехвата для всех запросов системы HTTP
, мы можем реализовать глобальный перехватчик GlobalInterceptor
и настроить его как spring Bean
.
@Component
public class MyGlobalInterceptor implements GlobalInterceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
// response 的 Header 加上 global
return response.newBuilder().header("global", "true").build();
}
}
Реализуйте интерфейс NetworkInterceptor
и настройте его как spring Bean
.
Retrofit
может адаптировать объект типа Call<T>
к типу возвращаемого значения метода с помощью CallAdapterFactory
. Компонент расширяет некоторые реализации CallAdapterFactory
:
BodyCallAdapterFactory
— синхронное выполнение HTTP
-запроса, адаптация содержимого ответа тела к типу возвращаемого значения метода.
Любой тип возвращаемого значения метода может использовать BodyCallAdapterFactory
, который имеет самый низкий приоритет.ResponseCallAdapterFactory
— синхронное выполнение HTTP
-запроса, адаптация содержимого ответа тела к Retrofit.Response<T>
, типу возвращаемого значения.
Только методы с типом возвращаемого значения Retrofit.Response<T>
могут использовать ResponseCallAdapterFactory
.Retrofit
выбирает соответствующий CallAdapterFactory
для выполнения адаптации в зависимости от типа возвращаемого значения метода. В настоящее время поддерживаются следующие типы возвращаемых значений:
— String
— адаптация содержимого тела ответа к строке.
— Базовые типы (Long
/Integer
/Boolean
/Float
/Double
) — адаптация содержимого тела ответа к базовому типу.
— Любой тип Java — адаптация содержимого тела ответа к соответствующему объекту Java.
— CompletableFuture<T>
— адаптация содержимого тела ответа к объекту CompletableFuture<T>
.
— Void
— не заботится о типе возвращаемого значения, можно использовать Void
.
— Response<T>
— адаптация тела ответа к Response<T>
.
— Call<T>
— без выполнения адаптации, напрямую возвращает объект Call<T>
.
— Mono<T>
— тип возврата Project Reactor
.
— Single<T>
— реактивный тип возврата Rxjava
(поддерживает Rxjava2/Rxjava3
).
— Completable
— реактивный тип возврата Rxjava
, HTTP
-запрос не имеет тела ответа (поддерживает Rxjava2/Rxjava3
).
Можно расширить CallAdapter.Factory
, унаследовав класс CallAdapter.Factory
.
Компонент поддерживает настройку глобального адаптера вызова через retrofit.global-call-adapter-factories
:
retrofit:
# 全局转换器工厂(组件扩展的 CallAdaptorFactory 工厂已经内置,这里请勿重复配置)
global-call-adapter-factories:
# ...
Для каждого интерфейса Java также можно указать CallAdapter.Factory
, используемый текущим интерфейсом, через @RetrofitClient.callAdapterFactories
.
Рекомендуется: настроить
CallAdapter.Factory
какSpring Bean
.
Retrofit
использует Converter
для преобразования объектов, аннотированных @Body
, в тело запроса и преобразования тела ответа в объект Java. Можно выбрать один из следующих Converter
:
— Gson (https://github.com/google/gson
): com.squareup.Retrofit:converter-gson
.
— Jackson (https://github.com/FasterXML/jackson
): com.squareup.Retrofit:converter-jackson
.
— Moshi (https://github.com/square/moshi/
): com.squareup.Retrofit:converter-moshi
.
— Protobuf (https://developers.google.com/protocol-buffers/
): com.squareup.Retrofit:converter-protobuf
.
— Wire (https://github.com/square/wire
): com.squareup.Retrofit:converter-wire
.
— Simple XML (http://simple.sourceforge.net/
): com.squareup.Retrofit:converter-simplexml
.
— JAXB (https://docs.oracle.com/javase/tutorial/jaxb/intro/index.html
): com.squareup.retrofit2:converter-jaxb
.
— fastJson: com.alibaba.fastjson.support.retrofit.Retrofit2ConverterFactory
.
Компонент поддерживает конфигурацию глобального Converter.Factory
через retrofit.global-converter-factories
, по умолчанию используется retrofit2.converter.jackson.JacksonConverterFactory
.
Если необходимо изменить конфигурацию Jackson
, вы можете самостоятельно переопределить конфигурацию bean JacksonConverterFactory
.
retrofit:
# 全局转换器工厂
global-converter-factories:
- com.github.lianjiatech.retrofit.spring.boot.core.BasicTypeConverterFactory
- retrofit2.converter.jackson.JacksonConverterFactory
Также можно указать текущий интерфейс, используя @RetrofitClient.converterFactories
.
Рекомендуется: настроить
Converter.Factory
какSpring Bean
.
Аннотации @RetrofitClient
, @Retry
, @Logging
, @Resilience4jDegrade
и другие поддерживают мета-аннотации, наследование и @AliasFor
.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Inherited
@RetrofitClient(baseUrl = "${test.baseUrl}")
@Logging(logLevel = LogLevel.WARN)
@Retry(intervalMs = 200)
public @interface MyRetrofitClient {
@AliasFor(annotation = RetrofitClient.class, attribute = "converterFactories")
Class<? extends Converter.Factory>[] converterFactories() default {GsonConverterFactory.class};
@AliasFor(annotation = Logging.class, attribute = "logStrategy")
LogStrategy logStrategy() default LogStrategy.BODY;
}
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )