我终于决定要放弃okhttp、httpClient,选择了这个牛逼的神仙工具!贼爽


HTTP请求相关注解,全部使用了retrofit原生注解。详细信息可参考官方文档:retrofit官方文档,以下是一个简单说明。

| 注解分类 | 支持的注解 |

| — | — |

| 请求方式 | @GET @HEAD @POST @PUT @DELETE @OPTIONS |

| 请求头 | @Header @HeaderMap @Headers |

| Query参数 | @Query @QueryMap @QueryName |

| path参数 | @Path |

| form-encoded参数 | @Field @FieldMap @FormUrlEncoded |

| 文件上传 | @Multipart @Part @PartMap |

| url参数 | @Url |

配置项说明


retrofit-spring-boot-starter支持了多个可配置的属性,用来应对不同的业务场景。您可以视情况进行修改,具体说明如下:

| 配置 | 默认值 | 说明 |

| — | — | — |

| enable-log | true | 启用日志打印 |

| logging-interceptor | DefaultLoggingInterceptor | 日志打印拦截器 |

| pool |

| 连接池配置 |

| disable-void-return-type | false | 禁用java.lang.Void返回类型 |

| retry-interceptor | DefaultRetryInterceptor | 请求重试拦截器 |

| global-converter-factories | JacksonConverterFactory | 全局转换器工厂 |

| global-call-adapter-factories | BodyCallAdapterFactory,ResponseCallAdapterFactory | 全局调用适配器工厂 |

| enable-degrade | false | 是否启用熔断降级 |

| degrade-type | sentinel | 熔断降级实现方式(目前仅支持Sentinel) |

| resource-name-parser | DefaultResourceNameParser | 熔断资源名称解析器,用于解析资源名称 |

yml配置方式:

retrofit:

enable-response-call-adapter: true

# 启用日志打印

enable-log: true

# 连接池配置

pool:

test1:

max-idle-connections: 3

keep-alive-second: 100

test2:

max-idle-connections: 5

keep-alive-second: 50

# 禁用void返回值类型

disable-void-return-type: false

# 日志打印拦截器

logging-interceptor: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor

# 请求重试拦截器

retry-interceptor: com.github.lianjiatech.retrofit.spring.boot.retry.DefaultRetryInterceptor

# 全局转换器工厂

global-converter-factories:

- retrofit2.converter.jackson.JacksonConverterFactory

# 全局调用适配器工厂

global-call-adapter-factories:

- com.github.lianjiatech.retrofit.spring.boot.core.BodyCallAdapterFactory

- com.github.lianjiatech.retrofit.spring.boot.core.ResponseCallAdapterFactory

# 是否启用熔断降级

enable-degrade: true

# 熔断降级实现方式

degrade-type: sentinel

# 熔断资源名称解析器

resource-name-parser: com.github.lianjiatech.retrofit.spring.boot.degrade.DefaultResourceNameParser

高级功能


自定义注入OkHttpClient

通常情况下,通过@RetrofitClient注解属性动态创建OkHttpClient对象能够满足大部分使用场景。但是在某些情况下,用户可能需要自定义OkHttpClient,这个时候,可以在接口上定义返回类型是OkHttpClient.Builder的静态方法来实现。代码示例如下:

@RetrofitClient(baseUrl = “http://ke.com”)

public interface HttpApi3 {

@OkHttpClientBuilder

static OkHttpClient.Builder okhttpClientBuilder() {

return new OkHttpClient.Builder()

.connectTimeout(1, TimeUnit.SECONDS)

.readTimeout(1, TimeUnit.SECONDS)

.writeTimeout(1, TimeUnit.SECONDS);

}

@GET

Result getPerson(@Url String url, @Query(“id”) Long id);

}

方法必须使用@OkHttpClientBuilder注解标记!

注解式拦截器

很多时候,我们希望某个接口下的某些http请求执行统一的拦截处理逻辑。为了支持这个功能,retrofit-spring-boot-starter提供了注解式拦截器,做到了基于url路径的匹配拦截。使用的步骤主要分为2步:

  1. 继承BasePathMatchInterceptor编写拦截处理器;

  2. 接口上使用@Intercept进行标注。如需配置多个拦截器,在接口上标注多个@Intercept注解即可!

下面以_给指定请求的url后面拼接timestamp时间戳_为例,介绍下如何使用注解式拦截器。

继承BasePathMatchInterceptor编写拦截处理器

@Component

public class TimeStampInterceptor extends BasePathMatchInterceptor {

@Override

public Response doIntercept(Chain chain) throws IOException {

Request request = chain.request();

HttpUrl url = request.url();

long timestamp = System.currentTimeMillis();

HttpUrl newUrl = url.newBuilder()

.addQueryParameter(“timestamp”, String.valueOf(timestamp))

.build();

Request newRequest = request.newBuilder()

.url(newUrl)

.build();

return chain.proceed(newRequest);

}

}

接口上使用@Intercept进行标注

@RetrofitClient(baseUrl = “${test.baseUrl}”)

@Intercept(handler = TimeStampInterceptor.class, include = {“/api/**”}, exclude = “/api/test/savePerson”)

public interface HttpApi {

@GET(“person”)

Result getPerson(@Query(“id”) Long id);

@POST(“savePerson”)

Result savePerson(@Body Person person);

}

上面的@Intercept配置表示:拦截HttpApi接口下/api/**路径下(排除/api/test/savePerson)的请求,拦截处理器使用TimeStampInterceptor

扩展注解式拦截器

有的时候,我们需要在拦截注解动态传入一些参数,然后再执行拦截的时候需要使用这个参数。这种时候,我们可以扩展实现自定义拦截注解自定义拦截注解必须使用@InterceptMark标记,并且注解中必须包括include()、exclude()、handler()属性信息。使用的步骤主要分为3步:

  1. 自定义拦截注解

  2. 继承BasePathMatchInterceptor编写拦截处理器

  3. 接口上使用自定义拦截注解;

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

自定义@Sign注解

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

@Documented

@InterceptMark

public @interface Sign {

/**

* 密钥key

* 支持占位符形式配置。

* @return

*/

String accessKeyId();

/**

* 密钥

* 支持占位符形式配置。

* @return

*/

String accessKeySecret();

/**

* 拦截器匹配路径

* @return

*/

String[] include() default {“/**”};

/**

* 拦截器排除匹配,排除指定路径拦截

* @return

*/

String[] exclude() default {};

/**

* 处理该注解的拦截器类

* 优先从spring容器获取对应的Bean,如果获取不到,则使用反射创建一个!

* @return

*/

Class<? extends BasePathMatchInterceptor> handler() default SignInterceptor.class;

}

扩展自定义拦截注解有以下2点需要注意:

  1. 自定义拦截注解必须使用@InterceptMark标记。

  2. 注解中必须包括include()、exclude()、handler()属性信息。

实现SignInterceptor

@Component

public class SignInterceptor extends BasePathMatchInterceptor {

private String accessKeyId;

private String accessKeySecret;

public void setAccessKeyId(String accessKeyId) {

this.accessKeyId = accessKeyId;

}

public void setAccessKeySecret(String accessKeySecret) {

this.accessKeySecret = accessKeySecret;

}

@Override

public Response doIntercept(Chain chain) throws IOException {

Request request = chain.request();

Request newReq = request.newBuilder()

.addHeader(“accessKeyId”, accessKeyId)

.addHeader(“accessKeySecret”, accessKeySecret)

.build();

return chain.proceed(newReq);

}

}

上述accessKeyIdaccessKeySecret字段值会依据@Sign注解的accessKeyId()accessKeySecret()值自动注入,如果@Sign指定的是占位符形式的字符串,则会取配置属性值进行注入。另外,accessKeyIdaccessKeySecret字段必须提供setter方法

接口上使用@Sign

@RetrofitClient(baseUrl = “${test.baseUrl}”)

@Sign(accessKeyId = “ t e s t . a c c e s s K e y I d " ,   a c c e s s K e y S e c r e t   =   " {test.accessKeyId}", accessKeySecret = " test.accessKeyId", accessKeySecret = "{test.accessKeySecret}”, exclude = {“/api/test/person”})

public interface HttpApi {

@GET(“person”)

Result getPerson(@Query(“id”) Long id);

@POST(“savePerson”)

Result savePerson(@Body Person person);

}

这样就能在指定url的请求上,自动加上签名信息了。

连接池管理

默认情况下,所有通过Retrofit发送的http请求都会使用max-idle-connections=5 keep-alive-second=300的默认连接池。当然,我们也可以在配置文件中配置多个自定义的连接池,然后通过@RetrofitClientpoolName属性来指定使用。比如我们要让某个接口下的请求全部使用poolName=test1的连接池,代码实现如下:

  1. 配置连接池。

retrofit:

# 连接池配置

pool:

test1:

max-idle-connections: 3

keep-alive-second: 100

test2:

max-idle-connections: 5

keep-alive-second: 50

  1. 通过@RetrofitClientpoolName属性来指定使用的连接池。

@RetrofitClient(baseUrl = “${test.baseUrl}”, poolName=“test1”)

public interface HttpApi {

@GET(“person”)

Result getPerson(@Query(“id”) Long id);

}

日志打印

很多情况下,我们希望将http请求日志记录下来。通过retrofit.enableLog配置可以全局控制日志是否开启。针对每个接口,可以通过@RetrofitClientenableLog控制是否开启,通过logLevellogStrategy,可以指定每个接口的日志打印级别以及日志打印策略。retrofit-spring-boot-starter支持了5种日志打印级别(ERROR, WARN, INFO, DEBUG, TRACE),默认INFO;支持了4种日志打印策略(NONE, BASIC, HEADERS, BODY),默认BASIC。4种日志打印策略含义如下:

  1. NONE:No logs.

  2. BASIC:Logs request and response lines.

  3. HEADERS:Logs request and response lines and their respective headers.

  4. BODY:Logs request and response lines and their respective headers and bodies (if present).

retrofit-spring-boot-starter默认使用了DefaultLoggingInterceptor执行真正的日志打印功能,其底层就是okhttp原生的HttpLoggingInterceptor。当然,你也可以自定义实现自己的日志打印拦截器,只需要继承BaseLoggingInterceptor(具体可以参考DefaultLoggingInterceptor的实现),然后在配置文件中进行相关配置即可。

retrofit:

# 日志打印拦截器

logging-interceptor: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor

请求重试

retrofit-spring-boot-starter支持请求重试功能,只需要在接口或者方法上加上@Retry注解即可。@Retry支持重试次数maxRetries、重试时间间隔intervalMs以及重试规则retryRules配置。重试规则支持三种配置:

  1. RESPONSE_STATUS_NOT_2XX:响应状态码不是2xx时执行重试;

  2. OCCUR_IO_EXCEPTION:发生IO异常时执行重试;

  3. OCCUR_EXCEPTION:发生任意异常时执行重试;

默认响应状态码不是2xx或者发生IO异常时自动进行重试。需要的话,你也可以继承BaseRetryInterceptor实现自己的请求重试拦截器,然后将其配置上去。

retrofit:

# 请求重试拦截器

retry-interceptor: com.github.lianjiatech.retrofit.spring.boot.retry.DefaultRetryInterceptor

错误解码器

HTTP发生请求错误(包括发生异常或者响应数据不符合预期)的时候,错误解码器可将HTTP相关信息解码到自定义异常中。你可以在@RetrofitClient注解的errorDecoder()指定当前接口的错误解码器,自定义错误解码器需要实现ErrorDecoder接口:

/**

* 错误解码器。ErrorDecoder.

* 当请求发生异常或者收到无效响应结果的时候,将HTTP相关信息解码到异常中,无效响应由业务自己判断

* When an exception occurs in the request or an invalid response result is received, the HTTP related information is decoded into the exception,

* and the invalid response is determined by the business itself.

* @author 陈添明

*/

public interface ErrorDecoder {

/**

* 当无效响应的时候,将HTTP信息解码到异常中,无效响应由业务自行判断。

* When the response is invalid, decode the HTTP information into the exception, invalid response is determined by business.

* @param request  request

* @param response response

* @return If it returns null, the processing is ignored and the processing continues with the original response.

*/

default RuntimeException invalidRespDecode(Request request, Response response) {

if (!response.isSuccessful()) {

throw RetrofitException.errorStatus(request, response);

}

return null;

}

/**

* 当请求发生IO异常时,将HTTP信息解码到异常中。

* When an IO exception occurs in the request, the HTTP information is decoded into the exception.

* @param request request

* @param cause   IOException

* @return RuntimeException

*/

default RuntimeException ioExceptionDecode(Request request, IOException cause) {

return RetrofitException.errorExecuting(request, cause);

}

/**

* 当请求发生除IO异常之外的其它异常时,将HTTP信息解码到异常中。

* When the request has an exception other than the IO exception, the HTTP information is decoded into the exception.

* @param request request

* @param cause   Exception

* @return RuntimeException

*/

default RuntimeException exceptionDecode(Request request, Exception cause) {

return RetrofitException.errorUnknown(request, cause);

}

}

全局拦截器


全局应用拦截器

如果我们需要对整个系统的的http请求执行统一的拦截处理,可以自定义实现全局拦截器BaseGlobalInterceptor, 并配置成spring容器中的bean!例如我们需要在整个系统发起的http请求,都带上来源信息。

@Component

public class SourceInterceptor extends BaseGlobalInterceptor {

@Override

public Response doIntercept(Chain chain) throws IOException {

Request request = chain.request();

Request newReq = request.newBuilder()

.addHeader(“source”, “test”)

.build();

return chain.proceed(newReq);

}

}

全局网络拦截器

只需要实现NetworkInterceptor接口 并配置成spring容器中的bean就支持自动织入全局网络拦截器。

熔断降级

在分布式服务架构中,对不稳定的外部服务进行熔断降级是保证服务高可用的重要措施之一。由于外部服务的稳定性是不能保证的,当外部服务不稳定时,响应时间会变长。相应地,调用方的响应时间也会变长,线程会产生堆积,最终可能耗尽调用方的线程池,导致整个服务不可用。因此我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定导致整体服务雪崩。

retrofit-spring-boot-starter支持熔断降级功能,底层基于Sentinel实现。具体来说,支持了熔断资源自发现注解式降级规则配置。如需使用熔断降级,只需要进行以下操作即可:

1. 开启熔断降级功能

默认情况下,熔断降级功能是关闭的,需要设置相应的配置项来开启熔断降级功能

retrofit:

# 是否启用熔断降级

enable-degrade: true

# 熔断降级实现方式(目前仅支持Sentinel)

degrade-type: sentinel

# 资源名称解析器

resource-name-parser: com.github.lianjiatech.retrofit.spring.boot.degrade.DefaultResourceNameParser

资源名称解析器用于实现用户自定义资源名称,默认配置是DefaultResourceNameParser,对应的资源名称格式为HTTP_OUT:GET:http://localhost:8080/api/degrade/test。用户可以继承BaseResourceNameParser类实现自己的资源名称解析器。

另外,由于熔断降级功能是可选的,因此启用熔断降级需要用户自行引入Sentinel依赖

com.alibaba.csp

sentinel-core

1.6.3

2. 配置降级规则(可选)

retrofit-spring-boot-starter支持注解式配置降级规则,通过@Degrade注解来配置降级规则@Degrade注解可以配置在接口或者方法上,配置在方法上的优先级更高。

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.METHOD, ElementType.TYPE})

@Documented

public @interface Degrade {

/**

* RT threshold or exception ratio threshold count.

*/

double count();

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

由于文案过于长,在此就不一一介绍了,这份Java后端架构进阶笔记内容包括:Java集合,JVM、Java并发、微服务、SpringNetty与 RPC 、网络、日志 、Zookeeper 、Kafka 、RabbitMQ 、Hbase 、MongoDB、Cassandra 、Java基础、负载均衡、数据库、一致性算法、Java算法、数据结构、分布式缓存等等知识详解。

image

本知识体系适合于所有Java程序员学习,关于以上目录中的知识点都有详细的讲解及介绍,掌握该知识点的所有内容对你会有一个质的提升,其中也总结了很多面试过程中遇到的题目以及有对应的视频解析总结。

image

image

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
中…(img-Fcc5aEv9-1712926201732)]

[外链图片转存中…(img-CfSLKbZx-1712926201733)]

[外链图片转存中…(img-eACwfDSU-1712926201733)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

由于文案过于长,在此就不一一介绍了,这份Java后端架构进阶笔记内容包括:Java集合,JVM、Java并发、微服务、SpringNetty与 RPC 、网络、日志 、Zookeeper 、Kafka 、RabbitMQ 、Hbase 、MongoDB、Cassandra 、Java基础、负载均衡、数据库、一致性算法、Java算法、数据结构、分布式缓存等等知识详解。

[外链图片转存中…(img-Z6hfSrDs-1712926201734)]

本知识体系适合于所有Java程序员学习,关于以上目录中的知识点都有详细的讲解及介绍,掌握该知识点的所有内容对你会有一个质的提升,其中也总结了很多面试过程中遇到的题目以及有对应的视频解析总结。

[外链图片转存中…(img-EVu0jHdt-1712926201734)]

[外链图片转存中…(img-Gw7g8TwU-1712926201734)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 22
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值