Skip to content

Commit bee9b0d

Browse files
Merge pull request #12 from LianjiaTech/develop
Develop
2 parents 8fdac42 + 40ce17c commit bee9b0d

File tree

16 files changed

+292
-44
lines changed

16 files changed

+292
-44
lines changed

README.md

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,18 @@
55
[![Build Status](https://api.travis-ci.com/LianjiaTech/retrofit-spring-boot-starter.svg?branch=master)](https://travis-ci.com/github/LianjiaTech/retrofit-spring-boot-starter)
66
[![Maven central](https://maven-badges.herokuapp.com/maven-central/com.github.lianjiatech/retrofit-spring-boot-starter/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.lianjiatech/retrofit-spring-boot-starter)
77
[![GitHub release](https://img.shields.io/github/v/release/lianjiatech/retrofit-spring-boot-starter.svg)](https://github.com/LianjiaTech/retrofit-spring-boot-starter/releases)
8-
[![Author](https://img.shields.io/badge/Author-%E9%99%88%E6%B7%BB%E6%98%8E-orange.svg?style=flat-square)](https://juejin.im/user/3562073404738584/posts)
8+
[![License](https://img.shields.io/badge/JDK-1.8+-4EB1BA.svg)](https://docs.oracle.com/javase/8/docs/index.html)
9+
[![License](https://img.shields.io/badge/springboot-1.x+-green.svg)](https://docs.spring.io/spring-boot/docs/2.1.5.RELEASE/reference/htmlsingle/)
10+
[![Author](https://img.shields.io/badge/Author-chentianming-orange.svg?style=flat-square)](https://juejin.im/user/3562073404738584/posts)
911
[![QQ-Group](https://img.shields.io/badge/QQ%E7%BE%A4-806714302-orange.svg?style=flat-square) ](https://img.ljcdn.com/hc-picture/6302d742-ebc8-4649-95cf-62ccf57a1add)
1012

11-
众所周知,`Retrofit`是适用于`Android``Java`且类型安全的HTTP客户端,其最大的特性的是**支持通过`接口`的方式发起HTTP请求**`spring-boot`是使用最广泛的Java开发框架但是`Retrofit`官方没有支持与`spring-boot`框架快速整合,从而加大了在`spring-boot`框架中引入`Retrofit`的难度
13+
> 众所周知,`Retrofit`是适用于`Android``Java`且类型安全的HTTP客户端,其最大的特性的是**支持通过`接口`的方式发起HTTP请求**`spring-boot`是使用最广泛的Java开发框架但是`Retrofit`官方没有支持与`spring-boot`框架快速整合,因此我们开发了`retrofit-spring-boot-starter`
1214
13-
**`retrofit-spring-boot-starter`实现了`Retrofit``spring-boot`框架快速整合,并且支持了部分功能增强,从而极大的简化`spring-boot`项目下`http`接口调用开发**
15+
**`retrofit-spring-boot-starter`实现了`Retrofit``spring-boot`框架快速整合,并且支持了诸多功能增强,极大简化开发**
1416

15-
<!--more-->
17+
| [快速使用](#快速使用) | [注解式拦截器](#注解式拦截器) | [连接池管理](#连接池管理) | [日志打印](#日志打印) | [异常信息格式化](#Http异常信息格式化器) | [请求重试](#请求重试) |[全局拦截器](#全局拦截器) | [调用适配器](#调用适配器) | [数据转换器](#数据转码器) |
1618

17-
> 支持`spring-boot 1.x/2.x`;支持`Java8`及以上版本。
19+
<!--more-->
1820

1921
## 快速使用
2022

@@ -24,7 +26,7 @@
2426
<dependency>
2527
<groupId>com.github.lianjiatech</groupId>
2628
<artifactId>retrofit-spring-boot-starter</artifactId>
27-
<version>2.0.4</version>
29+
<version>2.1.0</version>
2830
</dependency>
2931
```
3032

@@ -101,6 +103,7 @@ public class TestService {
101103
| pool | | 连接池配置 |
102104
| disable-void-return-type | false | 禁用java.lang.Void返回类型 |
103105
| http-exception-message-formatter | DefaultHttpExceptionMessageFormatter | Http异常信息格式化器 |
106+
| retry-interceptor | DefaultRetryInterceptor | 请求重试拦截器 |
104107

105108
`yml`配置方式:
106109

@@ -126,6 +129,8 @@ retrofit:
126129
logging-interceptor: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor
127130
# Http异常信息格式化器
128131
http-exception-message-formatter: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultHttpExceptionMessageFormatter
132+
# 请求重试拦截器
133+
retry-interceptor: com.github.lianjiatech.retrofit.spring.boot.retry.DefaultRetryInterceptor
129134
```
130135
131136
## 高级功能
@@ -187,7 +192,7 @@ public interface HttpApi {
187192
2. 继承`BasePathMatchInterceptor`编写拦截处理器
188193
3. 接口上使用自定义拦截注解;
189194

190-
例如我们需要**在请求头里面动态加入`accessKeyId`、`accessKeySecret`签名信息才能正常发起http请求**,这个时候可以**自定义一个加签拦截器注解`@Sign`**来实现。下面以自定义`@Sign`拦截注解为例进行说明。
195+
例如我们需要**在请求头里面动态加入`accessKeyId`、`accessKeySecret`签名信息才能正常发起http请求**,这个时候**可以自定义一个加签拦截器注解`@Sign`来实现**。下面以自定义`@Sign`拦截注解为例进行说明。
191196

192197

193198
#### 自定义`@Sign`注解
@@ -349,7 +354,43 @@ retrofit:
349354
http-exception-message-formatter: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultHttpExceptionMessageFormatter
350355
```
351356

352-
## 调用适配器 CallAdapter
357+
### 请求重试
358+
359+
`retrofit-spring-boot-starter`支持请求重试功能,只需要在接口或者方法上加上`@Retry`注解即可。**`@Retry`支持重试次数`maxRetries`、重试时间间隔`intervalMs`以及重试规则`retryRules`配置**。重试规则支持三种配置:
360+
361+
1. `RESPONSE_STATUS_NOT_2XX`:响应状态码不是`2xx`时执行重试;
362+
2. `OCCUR_IO_EXCEPTION`:发生IO异常时执行重试;
363+
3. `OCCUR_EXCEPTION`:发生任意异常时执行重试;
364+
365+
默认响应状态码不是`2xx`或者发生IO异常时自动进行重试。需要的话,你也可以继承`BaseRetryInterceptor`实现自己的请求重试拦截器,然后将其配置上去。
366+
367+
```yaml
368+
retrofit:
369+
# 请求重试拦截器
370+
retry-interceptor: com.github.lianjiatech.retrofit.spring.boot.retry.DefaultRetryInterceptor
371+
```
372+
373+
### 全局拦截器
374+
375+
如果我们需要对整个系统的的http请求执行统一的拦截处理,可以自定义实现全局拦截器`BaseGlobalInterceptor`, 并配置成`spring`中的`bean`!例如我们需要在整个系统发起的http请求,都带上来源信息。
376+
377+
```java
378+
@Component
379+
public class SourceInterceptor extends BaseGlobalInterceptor {
380+
@Override
381+
public Response doIntercept(Chain chain) throws IOException {
382+
Request request = chain.request();
383+
Request newReq = request.newBuilder()
384+
.addHeader("source", "test")
385+
.build();
386+
return chain.proceed(newReq);
387+
}
388+
}
389+
```
390+
391+
## 调用适配器和数据转码器
392+
393+
### 调用适配器
353394

354395
`Retrofit`可以通过调用适配器`CallAdapterFactory`将`Call<T>`对象适配成接口方法的返回值类型。`retrofit-spring-boot-starter`扩展2种`CallAdapterFactory`实现:
355396

@@ -422,7 +463,7 @@ retrofit:
422463

423464
> 自定义配置的`CallAdapter.Factory`优先级更高!
424465

425-
## 数据转码器 Converter
466+
### 数据转码器
426467

427468
`Retrofit`使用`Converter`将`@Body`注解标注的对象转换成请求体,将响应体数据转换成一个`Java`对象,可以选用以下几种`Converter`:
428469

@@ -440,24 +481,6 @@ retrofit:
440481
> 自定义配置的`Converter.Factory`优先级更高!
441482

442483

443-
## 全局拦截器 BaseGlobalInterceptor
444-
445-
如果我们需要对整个系统的的http请求执行统一的拦截处理,可以自定义实现全局拦截器`BaseGlobalInterceptor`, 并配置成`spring`中的`bean`!例如我们需要在整个系统发起的http请求,都带上来源信息。
446-
447-
```java
448-
@Component
449-
public class SourceInterceptor extends BaseGlobalInterceptor {
450-
@Override
451-
public Response doIntercept(Chain chain) throws IOException {
452-
Request request = chain.request();
453-
Request newReq = request.newBuilder()
454-
.addHeader("source", "test")
455-
.build();
456-
return chain.proceed(newReq);
457-
}
458-
}
459-
```
460-
461484
## 其他功能示例
462485

463486
### 上传文件示例
@@ -493,13 +516,6 @@ Void upload(@Part MultipartBody.Part file);
493516
494517
```
495518

496-
### TODO
497-
498-
- [X] 考虑使用springboot JacksonAutoConfiguration提供的ObjectMapper替代自定义的
499-
- [ ] 缓存支持:支持客户端内存级别缓存,降低调用接口频率
500-
- [ ] BasePathMatchInterceptor自定义Scope,减少内存占用
501-
- [ ] 整合熔断降级
502-
503519
## 反馈建议
504520

505521
如有任何问题,欢迎提issue或者加QQ群反馈。

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.github.lianjiatech</groupId>
88
<artifactId>retrofit-spring-boot-starter</artifactId>
9-
<version>2.0.4</version>
9+
<version>2.1.0</version>
1010

1111
<name>retrofit-spring-boot-starter</name>
1212
<description>retrofit-spring-boot-starter</description>

src/main/java/com/github/lianjiatech/retrofit/spring/boot/annotation/RetrofitClient.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252

5353
/**
5454
* 针对当前接口是否启用日志打印
55+
*
5556
* @return
5657
*/
5758
boolean enableLog() default true;

src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitAutoConfiguration.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.github.lianjiatech.retrofit.spring.boot.interceptor.BaseGlobalInterceptor;
99
import com.github.lianjiatech.retrofit.spring.boot.interceptor.BaseHttpExceptionMessageFormatter;
1010
import com.github.lianjiatech.retrofit.spring.boot.interceptor.HttpExceptionMessageFormatterInterceptor;
11+
import com.github.lianjiatech.retrofit.spring.boot.retry.BaseRetryInterceptor;
1112
import okhttp3.ConnectionPool;
1213
import org.springframework.beans.BeansException;
1314
import org.springframework.beans.factory.annotation.Autowired;
@@ -94,6 +95,10 @@ public RetrofitConfigBean retrofitConfigBean(@Autowired ObjectMapper objectMappe
9495
Collection<BaseGlobalInterceptor> globalInterceptors = getBeans(BaseGlobalInterceptor.class);
9596
retrofitConfigBean.setGlobalInterceptors(globalInterceptors);
9697

98+
// retryInterceptor
99+
Class<? extends BaseRetryInterceptor> retryInterceptor = retrofitProperties.getRetryInterceptor();
100+
retrofitConfigBean.setRetryInterceptor(retryInterceptor.newInstance());
101+
97102
return retrofitConfigBean;
98103
}
99104

src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitConfigBean.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.github.lianjiatech.retrofit.spring.boot.config;
22

33
import com.github.lianjiatech.retrofit.spring.boot.interceptor.BaseGlobalInterceptor;
4+
import com.github.lianjiatech.retrofit.spring.boot.retry.BaseRetryInterceptor;
45
import com.github.lianjiatech.retrofit.spring.boot.interceptor.HttpExceptionMessageFormatterInterceptor;
56
import okhttp3.ConnectionPool;
67
import retrofit2.CallAdapter;
@@ -27,6 +28,8 @@ public class RetrofitConfigBean {
2728

2829
private Collection<BaseGlobalInterceptor> globalInterceptors;
2930

31+
private BaseRetryInterceptor retryInterceptor;
32+
3033
public RetrofitProperties getRetrofitProperties() {
3134
return retrofitProperties;
3235
}
@@ -74,4 +77,12 @@ public Collection<BaseGlobalInterceptor> getGlobalInterceptors() {
7477
public void setGlobalInterceptors(Collection<BaseGlobalInterceptor> globalInterceptors) {
7578
this.globalInterceptors = globalInterceptors;
7679
}
80+
81+
public BaseRetryInterceptor getRetryInterceptor() {
82+
return retryInterceptor;
83+
}
84+
85+
public void setRetryInterceptor(BaseRetryInterceptor retryInterceptor) {
86+
this.retryInterceptor = retryInterceptor;
87+
}
7788
}

src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitProperties.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@
33

44
import com.github.lianjiatech.retrofit.spring.boot.core.BodyCallAdapterFactory;
55
import com.github.lianjiatech.retrofit.spring.boot.core.ResponseCallAdapterFactory;
6-
import com.github.lianjiatech.retrofit.spring.boot.interceptor.BaseHttpExceptionMessageFormatter;
7-
import com.github.lianjiatech.retrofit.spring.boot.interceptor.BaseLoggingInterceptor;
8-
import com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultHttpExceptionMessageFormatter;
9-
import com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor;
6+
import com.github.lianjiatech.retrofit.spring.boot.interceptor.*;
7+
import com.github.lianjiatech.retrofit.spring.boot.retry.BaseRetryInterceptor;
108
import org.springframework.boot.context.properties.ConfigurationProperties;
119

1210
import java.util.LinkedHashMap;
@@ -50,6 +48,12 @@ public class RetrofitProperties {
5048
*/
5149
private Class<? extends BaseHttpExceptionMessageFormatter> httpExceptionMessageFormatter = DefaultHttpExceptionMessageFormatter.class;
5250

51+
52+
/**
53+
* 请求重试拦截器
54+
*/
55+
private Class<? extends BaseRetryInterceptor> retryInterceptor = BaseRetryInterceptor.class;
56+
5357
public Class<? extends BaseHttpExceptionMessageFormatter> getHttpExceptionMessageFormatter() {
5458
return httpExceptionMessageFormatter;
5559
}
@@ -115,4 +119,12 @@ public boolean isDisableVoidReturnType() {
115119
public void setDisableVoidReturnType(boolean disableVoidReturnType) {
116120
this.disableVoidReturnType = disableVoidReturnType;
117121
}
122+
123+
public Class<? extends BaseRetryInterceptor> getRetryInterceptor() {
124+
return retryInterceptor;
125+
}
126+
127+
public void setRetryInterceptor(Class<? extends BaseRetryInterceptor> retryInterceptor) {
128+
this.retryInterceptor = retryInterceptor;
129+
}
118130
}

src/main/java/com/github/lianjiatech/retrofit/spring/boot/core/RetrofitFactoryBean.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44
import com.github.lianjiatech.retrofit.spring.boot.annotation.RetrofitClient;
55
import com.github.lianjiatech.retrofit.spring.boot.config.RetrofitConfigBean;
66
import com.github.lianjiatech.retrofit.spring.boot.config.RetrofitProperties;
7-
import com.github.lianjiatech.retrofit.spring.boot.interceptor.BaseGlobalInterceptor;
8-
import com.github.lianjiatech.retrofit.spring.boot.interceptor.BaseLoggingInterceptor;
9-
import com.github.lianjiatech.retrofit.spring.boot.interceptor.BasePathMatchInterceptor;
10-
import com.github.lianjiatech.retrofit.spring.boot.interceptor.HttpExceptionMessageFormatterInterceptor;
7+
import com.github.lianjiatech.retrofit.spring.boot.interceptor.*;
118
import com.github.lianjiatech.retrofit.spring.boot.util.BeanExtendUtils;
129
import okhttp3.ConnectionPool;
1310
import okhttp3.Interceptor;
@@ -146,6 +143,10 @@ private synchronized OkHttpClient getOkHttpClient(Class<?> retrofitClientInterfa
146143
if (httpExceptionMessageFormatterInterceptor != null) {
147144
okHttpClientBuilder.addInterceptor(httpExceptionMessageFormatterInterceptor);
148145
}
146+
// 请求重试拦截器
147+
Interceptor retryInterceptor = retrofitConfigBean.getRetryInterceptor();
148+
okHttpClientBuilder.addInterceptor(retryInterceptor);
149+
149150
return okHttpClientBuilder.build();
150151
}
151152

src/main/java/com/github/lianjiatech/retrofit/spring/boot/interceptor/HttpExceptionMessageFormatterInterceptor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
/**
1010
* http异常信息格式化
11+
*
1112
* @author 陈添明
1213
*/
1314
public class HttpExceptionMessageFormatterInterceptor implements Interceptor {
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.github.lianjiatech.retrofit.spring.boot.retry;
2+
3+
import okhttp3.Interceptor;
4+
import okhttp3.Request;
5+
import okhttp3.Response;
6+
import retrofit2.Invocation;
7+
8+
import java.io.IOException;
9+
import java.lang.reflect.Method;
10+
11+
/**
12+
* 请求重试拦截器
13+
*
14+
* @author 陈添明
15+
*/
16+
public abstract class BaseRetryInterceptor implements Interceptor {
17+
18+
19+
private static final int LIMIT_RETRIES = 10;
20+
21+
@Override
22+
public Response intercept(Chain chain) throws IOException {
23+
Request request = chain.request();
24+
Invocation invocation = request.tag(Invocation.class);
25+
assert invocation != null;
26+
Method method = invocation.method();
27+
// 获取重试配置
28+
Retry retry;
29+
if (method.isAnnotationPresent(Retry.class)) {
30+
retry = method.getAnnotation(Retry.class);
31+
} else {
32+
Class<?> declaringClass = method.getDeclaringClass();
33+
retry = declaringClass.getAnnotation(Retry.class);
34+
}
35+
if (retry == null) {
36+
// 不用重试
37+
return chain.proceed(request);
38+
}
39+
// 重试
40+
int maxRetries = retry.maxRetries();
41+
int intervalMs = retry.intervalMs();
42+
RetryRule[] retryRules = retry.retryRules();
43+
// 最多重试10次
44+
maxRetries = maxRetries > LIMIT_RETRIES ? LIMIT_RETRIES : maxRetries;
45+
try {
46+
return retryIntercept(maxRetries, intervalMs, retryRules, chain);
47+
} catch (InterruptedException e) {
48+
throw new RuntimeException(e);
49+
}
50+
}
51+
52+
53+
/**
54+
* 执行可重试请求
55+
* 这里访问级别设置为protected,可方便业务个性化扩展
56+
*
57+
* @param maxRetries 最大重试次数
58+
* @param intervalMs 重试时间间隔
59+
* @param retryRules 重试规则
60+
* @param chain 执行链
61+
* @return 请求响应
62+
* @throws IOException 执行IO异常
63+
* @throws InterruptedException 中断异常
64+
*/
65+
protected abstract Response retryIntercept(int maxRetries, int intervalMs, RetryRule[] retryRules, Chain chain) throws IOException, InterruptedException;
66+
67+
}

0 commit comments

Comments
 (0)