From e7a1a5e5becfc78f68dd8a6126cca70e92040473 Mon Sep 17 00:00:00 2001 From: chentianming Date: Tue, 24 May 2022 16:49:20 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E8=87=AA=E5=AE=9A=E4=B9=89Ok?= =?UTF-8?q?HttpClient=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 123 +++--------------- pom.xml | 2 +- .../spring/boot/config/PoolConfig.java | 18 --- .../config/RetrofitAutoConfiguration.java | 35 +++-- .../boot/config/RetrofitConfigBean.java | 4 - .../boot/config/RetrofitProperties.java | 43 +----- .../retrofit/spring/boot/core/Constants.java | 20 +++ .../spring/boot/core/RetrofitClient.java | 82 +----------- .../spring/boot/core/RetrofitFactoryBean.java | 71 +--------- .../boot/test/RetrofitTestApplication.java | 38 ++++++ .../test/custom/okhttp/CustomOkHttpTest.java | 78 +++++++++++ .../custom/okhttp/CustomOkHttpTestApi.java | 23 ++++ .../spring/boot/test/http/HttpApi.java | 2 +- src/test/resources/application.yml | 18 --- src/test/resources/default-config.yml | 18 --- 15 files changed, 210 insertions(+), 365 deletions(-) delete mode 100644 src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/PoolConfig.java create mode 100644 src/main/java/com/github/lianjiatech/retrofit/spring/boot/core/Constants.java create mode 100644 src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/custom/okhttp/CustomOkHttpTest.java create mode 100644 src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/custom/okhttp/CustomOkHttpTestApi.java diff --git a/README.md b/README.md index caf3724..7d57fca 100644 --- a/README.md +++ b/README.md @@ -29,15 +29,13 @@ gitee项目地址:[https://gitee.com/lianjiatech/retrofit-spring-boot-starter] ## 功能特性 -- [x] [超时时间设置](#超时时间设置) +- [x] [自定义OkHttpClient属性](#自定义OkHttpClient属性) - [x] [注解式拦截器](#注解式拦截器) - [x] [日志打印](#日志打印) - [x] [请求重试](#请求重试) - [x] [熔断降级](#熔断降级) - [x] [错误解码器](#错误解码器) -- [x] [自定义注入OkHttpClient](#自定义注入OkHttpClient) - [x] [微服务之间的HTTP调用](#微服务之间的HTTP调用) -- [x] [连接池管理](#连接池管理) - [x] [全局拦截器](#全局拦截器) - [x] [调用适配器](#调用适配器) - [x] [数据转换器](#数据转码器) @@ -52,7 +50,7 @@ gitee项目地址:[https://gitee.com/lianjiatech/retrofit-spring-boot-starter] com.github.lianjiatech retrofit-spring-boot-starter - 2.3.2 + 2.3.3 ``` @@ -65,7 +63,7 @@ gitee项目地址:[https://gitee.com/lianjiatech/retrofit-spring-boot-starter] com.github.lianjiatech retrofit-spring-boot-starter - 2.3.2 + 2.3.3 com.squareup.okhttp3 @@ -151,15 +149,6 @@ public class TestService { ```yaml retrofit: - # 连接池配置 - pool: - # default连接池 - default: - # 最大空闲连接数 - max-idle-connections: 5 - # 连接保活时间(秒) - keep-alive-second: 300 - # 全局转换器工厂 global-converter-factories: - com.github.lianjiatech.retrofit.spring.boot.core.BasicTypeConverterFactory @@ -178,7 +167,7 @@ retrofit: # 全局日志打印策略 log-strategy: basic - # 重试配置 + # 全局重试配置 global-retry: # 是否启用全局重试 enable: false @@ -227,53 +216,39 @@ retrofit: # 指定断路器应保持半开多长时间的等待持续时间,可选配置,大于1才是有效配置。 max-wait-duration-in-half-open-state-seconds: 0 # 忽略的异常类列表,只有配置值之后才会加载。 - ignore-exceptions: [] + ignore-exceptions: [ ] # 记录的异常类列表,只有配置值之后才会加载。 - record-exceptions: [] + record-exceptions: [ ] # 慢调用比例阈值 slow-call-rate-threshold: 100 # 慢调用阈值秒数,超过该秒数视为慢调用 slow-call-duration-threshold-seconds: 60 # 启用可写堆栈跟踪的标志 writable-stack-trace-enabled: true - - # 全局连接超时时间 - global-connect-timeout-ms: 10000 - # 全局读取超时时间 - global-read-timeout-ms: 10000 - # 全局写入超时时间 - global-write-timeout-ms: 10000 - # 全局完整调用超时时间 - global-call-timeout-ms: 0 - ``` ## 高级功能 -### 超时时间设置 - -`retrofit-spring-boot-starter`支持两种方式设置超时时间,一种是全局超时时间设置,另一种是注解超时时间设置。 +### 自定义OkHttpClient属性 -#### 全局超时时间设置 +根据`@RetrofitClient`的`baseOkHttpClientBeanName`,根据该名称从Spring容器中对应的`OkHttpClient`来初始化当前接口的`OkHttpClient`。 +通过这种方式,用户可以配置超时时间、代理、连接池、分发等等`OkHttpClient`属性。 -**在yaml文件中可配置全局超时时间,对所有接口生效**。 +默认是`defaultBaseOkHttpClient`,可以按下面方式覆盖Spring配置: -```yaml -retrofit: - # 全局连接超时时间 - global-connect-timeout-ms: 5000 - # 全局读取超时时间 - global-read-timeout-ms: 5000 - # 全局写入超时时间 - global-write-timeout-ms: 5000 - # 全局完整调用超时时间 - global-call-timeout-ms: 0 +```java +@Bean +@Primary +OkHttpClient defaultBaseOkHttpClient(){ + return new OkHttpClient.Builder() + .addInterceptor(chain->{ + log.info("=======替换defaultBaseOkHttpClient====="); + return chain.proceed(chain.request()); + }) + .build(); + } ``` -#### 注解式超时时间设置 - -在`@RetrofitClient`注解上可以设置超时时间,针对当前接口生效,优先级更高。具体字段有`connectTimeoutMs`、`readTimeoutMs`、`writeTimeoutMs`、`callTimeoutMs`等。 - ### 注解式拦截器 很多时候,我们希望某个接口下的某些http请求执行统一的拦截处理逻辑。为了支持这个功能,`retrofit-spring-boot-starter`提供了**注解式拦截器**,做到了**基于url路径的匹配拦截**。使用的步骤主要分为2步: @@ -696,32 +671,6 @@ public interface ErrorDecoder { ``` -### 自定义注入OkHttpClient - -通常情况下,通过`@RetrofitClient`注解属性动态创建`OkHttpClient`对象能够满足大部分使用场景。但是在某些情况下,用户可能需要自定义`OkHttpClient` -,这个时候,可以在接口上定义返回类型是`OkHttpClient.Builder`的静态方法来实现。代码示例如下: - -```java - -@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调用 为了能够使用微服务调用,需要进行如下配置: @@ -749,36 +698,6 @@ public interface ApiCountService { } ``` -### 连接池管理 - -默认情况下,所有通过`Retrofit`发送的http请求都会使用`max-idle-connections=5 keep-alive-second=300` -的默认连接池。当然,我们也可以在配置文件中配置多个自定义的连接池,然后通过`@RetrofitClient`的`poolName`属性来指定使用。比如我们要让某个接口下的请求全部使用`poolName=test1`的连接池,代码实现如下: - -1. 配置连接池。 - - ```yaml - retrofit: - # 连接池配置 - pool: - # test1连接池配置 - test1: - # 最大空闲连接数 - max-idle-connections: 3 - # 连接保活时间(秒) - keep-alive-second: 100 - ``` - -2. 通过`@RetrofitClient`的`poolName`属性来指定使用的连接池。 - - ```java - @RetrofitClient(baseUrl = "${test.baseUrl}", poolName="test1") - public interface HttpApi { - - @GET("person") - Result getPerson(@Query("id") Long id); - } - ``` - ## 全局拦截器 ### 全局应用拦截器 diff --git a/pom.xml b/pom.xml index d440821..0307e88 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.github.lianjiatech retrofit-spring-boot-starter - 2.3.2 + 2.3.3 retrofit-spring-boot-starter retrofit-spring-boot-starter diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/PoolConfig.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/PoolConfig.java deleted file mode 100644 index 4786049..0000000 --- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/PoolConfig.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.github.lianjiatech.retrofit.spring.boot.config; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -/** - * @author 陈添明 - */ -@Data -@NoArgsConstructor -@AllArgsConstructor -public class PoolConfig { - - private int maxIdleConnections; - - private long keepAliveSecond; -} \ No newline at end of file diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitAutoConfiguration.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitAutoConfiguration.java index 8bcf097..ca0e11c 100644 --- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitAutoConfiguration.java +++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitAutoConfiguration.java @@ -1,9 +1,6 @@ package com.github.lianjiatech.retrofit.spring.boot.config; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -13,6 +10,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Primary; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.DeserializationFeature; @@ -20,6 +18,7 @@ import com.github.lianjiatech.retrofit.spring.boot.core.AutoConfiguredRetrofitScannerRegistrar; import com.github.lianjiatech.retrofit.spring.boot.core.BasicTypeConverterFactory; import com.github.lianjiatech.retrofit.spring.boot.core.BodyCallAdapterFactory; +import com.github.lianjiatech.retrofit.spring.boot.core.Constants; import com.github.lianjiatech.retrofit.spring.boot.core.ErrorDecoder; import com.github.lianjiatech.retrofit.spring.boot.core.PathMatchInterceptorBdfProcessor; import com.github.lianjiatech.retrofit.spring.boot.core.ResponseCallAdapterFactory; @@ -36,7 +35,7 @@ import com.github.lianjiatech.retrofit.spring.boot.retry.RetryInterceptor; import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry; -import okhttp3.ConnectionPool; +import okhttp3.OkHttpClient; import retrofit2.converter.jackson.JacksonConverterFactory; /** @@ -77,16 +76,6 @@ public RetrofitConfigBean retrofitConfigBean(@Autowired(required = false) Retrof retrofitConfigBean.setRetryInterceptor(retryInterceptor); retrofitConfigBean.setLoggingInterceptor(loggingInterceptor); retrofitConfigBean.setErrorDecoderInterceptor(errorDecoderInterceptor); - - Map poolRegistry = new HashMap<>(4); - retrofitProperties.getPool().forEach((poolName, poolConfig) -> { - long keepAliveSecond = poolConfig.getKeepAliveSecond(); - int maxIdleConnections = poolConfig.getMaxIdleConnections(); - ConnectionPool connectionPool = - new ConnectionPool(maxIdleConnections, keepAliveSecond, TimeUnit.SECONDS); - poolRegistry.put(poolName, connectionPool); - }); - retrofitConfigBean.setPoolRegistry(poolRegistry); retrofitConfigBean.setGlobalCallAdapterFactoryClasses(retrofitProperties.getGlobalCallAdapterFactories()); retrofitConfigBean.setGlobalConverterFactoryClasses(retrofitProperties.getGlobalConverterFactories()); return retrofitConfigBean; @@ -126,7 +115,7 @@ public RetryInterceptor retryInterceptor() { @Bean @ConditionalOnMissingBean - public LoggingInterceptor logInterceptor() { + public LoggingInterceptor loggingInterceptor() { return new LoggingInterceptor(retrofitProperties.getGlobalLog()); } @@ -142,18 +131,26 @@ ServiceChooseInterceptor serviceChooseInterceptor(@Autowired ServiceInstanceChoo return new ServiceChooseInterceptor(serviceInstanceChooser); } + @Bean + @Primary + @ConditionalOnMissingBean(name = Constants.DEFAULT_BASE_OK_HTTP_CLIENT) + OkHttpClient defaultBaseOkHttpClient() { + return new OkHttpClient.Builder() + .build(); + } + @Bean @ConditionalOnMissingBean - @ConditionalOnClass(name = "com.alibaba.csp.sentinel.SphU") - @ConditionalOnProperty(name = "retrofit.degrade.degrade-type", havingValue = RetrofitDegrade.SENTINEL) + @ConditionalOnClass(name = Constants.SPH_U_CLASS_NAME) + @ConditionalOnProperty(name = Constants.DEGRADE_TYPE, havingValue = RetrofitDegrade.SENTINEL) public RetrofitDegrade sentinelRetrofitDegrade() { return new SentinelRetrofitDegrade(retrofitProperties.getDegrade().getGlobalSentinelDegrade()); } @Bean @ConditionalOnMissingBean - @ConditionalOnClass(name = "io.github.resilience4j.circuitbreaker.CircuitBreaker") - @ConditionalOnProperty(name = "retrofit.degrade.degrade-type", havingValue = RetrofitDegrade.RESILIENCE4J) + @ConditionalOnClass(name = Constants.CIRCUIT_BREAKER_CLASS_NAME) + @ConditionalOnProperty(name = Constants.DEGRADE_TYPE, havingValue = RetrofitDegrade.RESILIENCE4J) public RetrofitDegrade resilience4jRetrofitDegrade() { return new Resilience4jRetrofitDegrade(CircuitBreakerRegistry.ofDefaults(), retrofitProperties.getDegrade().getGlobalResilience4jDegrade()); diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitConfigBean.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitConfigBean.java index 24fa53f..1858fc1 100644 --- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitConfigBean.java +++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitConfigBean.java @@ -2,7 +2,6 @@ import java.util.Collections; import java.util.List; -import java.util.Map; import com.github.lianjiatech.retrofit.spring.boot.degrade.RetrofitDegrade; import com.github.lianjiatech.retrofit.spring.boot.interceptor.ErrorDecoderInterceptor; @@ -13,7 +12,6 @@ import com.github.lianjiatech.retrofit.spring.boot.retry.RetryInterceptor; import lombok.Data; -import okhttp3.ConnectionPool; import retrofit2.CallAdapter; import retrofit2.Converter; @@ -25,8 +23,6 @@ public class RetrofitConfigBean { private final RetrofitProperties retrofitProperties; - private Map poolRegistry; - private List globalInterceptors; private List networkInterceptors; diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitProperties.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitProperties.java index 4fdabec..3cc1ca7 100644 --- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitProperties.java +++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitProperties.java @@ -1,13 +1,11 @@ package com.github.lianjiatech.retrofit.spring.boot.config; -import java.util.LinkedHashMap; -import java.util.Map; - import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.NestedConfigurationProperty; import com.github.lianjiatech.retrofit.spring.boot.core.BasicTypeConverterFactory; import com.github.lianjiatech.retrofit.spring.boot.core.BodyCallAdapterFactory; +import com.github.lianjiatech.retrofit.spring.boot.core.Constants; import com.github.lianjiatech.retrofit.spring.boot.core.ResponseCallAdapterFactory; import com.github.lianjiatech.retrofit.spring.boot.degrade.DegradeProperty; import com.github.lianjiatech.retrofit.spring.boot.log.GlobalLogProperty; @@ -21,19 +19,10 @@ /** * @author 陈添明 */ -@ConfigurationProperties(prefix = "retrofit") +@ConfigurationProperties(prefix = Constants.RETROFIT) @Data public class RetrofitProperties { - private static final String DEFAULT_POOL = "default"; - - /** - * 连接池配置 - * Connection pool configuration - */ - @NestedConfigurationProperty - private Map pool = new LinkedHashMap<>(); - /** * 全局重试配置 * retry config @@ -55,26 +44,6 @@ public class RetrofitProperties { @NestedConfigurationProperty private GlobalLogProperty globalLog = new GlobalLogProperty(); - /** - * 全局连接超时时间 - */ - private int globalConnectTimeoutMs = 10_000; - - /** - * 全局读取超时时间 - */ - private int globalReadTimeoutMs = 10_000; - - /** - * 全局写入超时时间 - */ - private int globalWriteTimeoutMs = 10_000; - - /** - * 全局完整调用超时时间 - */ - private int globalCallTimeoutMs = 0; - /** * 全局转换器工厂,转换器实例优先从Spring容器获取,如果没有获取到,则反射创建。 * global converter factories, The converter instance is first obtained from the Spring container. If it is not obtained, it is created by reflection. @@ -91,12 +60,4 @@ public class RetrofitProperties { private Class[] globalCallAdapterFactories = (Class[])new Class[] {BodyCallAdapterFactory.class, ResponseCallAdapterFactory.class}; - - public Map getPool() { - if (!pool.isEmpty()) { - return pool; - } - pool.put(DEFAULT_POOL, new PoolConfig(5, 300)); - return pool; - } } diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/core/Constants.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/core/Constants.java new file mode 100644 index 0000000..17891a7 --- /dev/null +++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/core/Constants.java @@ -0,0 +1,20 @@ +package com.github.lianjiatech.retrofit.spring.boot.core; + +/** + * @author 陈添明 + * @since 2022/5/24 1:31 下午 + */ +public interface Constants { + + String STR_EMPTY = ""; + + String DEFAULT_BASE_OK_HTTP_CLIENT = "defaultBaseOkHttpClient"; + + String SPH_U_CLASS_NAME = "com.alibaba.csp.sentinel.SphU"; + + String DEGRADE_TYPE = "retrofit.degrade.degrade-type"; + + String CIRCUIT_BREAKER_CLASS_NAME = "io.github.resilience4j.circuitbreaker.CircuitBreaker"; + + String RETROFIT = "retrofit"; +} diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/core/RetrofitClient.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/core/RetrofitClient.java index 2614fbf..41075ce 100644 --- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/core/RetrofitClient.java +++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/core/RetrofitClient.java @@ -29,21 +29,19 @@ * Can be specified as property key, eg: ${propertyKey}. * If baseUrl is not configured, you must configure serviceId and path optional configuration. * - * - * @return baseUrl */ - String baseUrl() default ""; + String baseUrl() default Constants.STR_EMPTY; /** * The name of the service. * Can be specified as property key, eg: ${propertyKey}. */ - String serviceId() default ""; + String serviceId() default Constants.STR_EMPTY; /** * Path prefix to be used by all method-level mappings. */ - String path() default ""; + String path() default Constants.STR_EMPTY; /** * 适用于当前接口的转换器工厂,优先级比全局转换器工厂更高。转换器实例优先从Spring容器获取,如果没有获取到,则反射创建。 @@ -80,17 +78,9 @@ * The invalid response is determined by the business itself. * In general, the invalid response corresponding to each service is different, you can customize the corresponding {@link ErrorDecoder}, and then configure it here. * - * @return ErrorDecoder */ Class errorDecoder() default ErrorDecoder.DefaultErrorDecoder.class; - /** - * connection pool name - * - * @return connection pool name - */ - String poolName() default "default"; - /** * When calling {@link Retrofit#create(Class)} on the resulting {@link Retrofit} instance, eagerly validate the * configuration of all methods in the supplied interface. @@ -100,70 +90,8 @@ boolean validateEagerly() default false; /** - * Sets the default connect timeout for new connections. A value of 0 means no timeout, - * otherwise values must be between 1 and Integer.MAX_VALUE when converted to milliseconds. - * If it is configured as -1, the global default configuration is used. - * - * @return connectTimeoutMs - */ - int connectTimeoutMs() default -1; - - /** - * Sets the default read timeout for new connections. A value of 0 means no timeout, - * otherwise values must be between 1 and Integer.MAX_VALUE when converted to milliseconds. - * If it is configured as -1, the global default configuration is used. - * - * @return readTimeoutMs - */ - int readTimeoutMs() default -1; - - /** - * Sets the default write timeout for new connections. A value of 0 means no timeout, - * otherwise values must be between 1 and Integer.MAX_VALUE when converted to milliseconds. - * If it is configured as -1, the global default configuration is used. - * - * @return writeTimeoutMs - */ - int writeTimeoutMs() default -1; - - /** - * Sets the default timeout for complete calls. A value of 0 means no timeout, - * otherwise values must be between 1 and Integer.MAX_VALUE when converted to milliseconds. - * - * @return callTimeout - */ - int callTimeoutMs() default -1; - - /** - * Sets the interval between HTTP/2 and web socket pings initiated by this client. - * Use this to automatically send ping frames until either the connection fails or it is closed. - * This keeps the connection alive and may detect connectivity failures. - * - * @return pingInterval - */ - int pingIntervalMs() default 0; - - /** - * Configure this client to allow protocol redirects from HTTPS to HTTP and from HTTP to HTTPS. - * Redirects are still first restricted by followRedirects. Defaults to true. - * - * @return followSslRedirects - */ - boolean followSslRedirects() default true; - - /** - * Configure this client to follow redirects. If unset, redirects will be followed. - * - * @return followRedirects - */ - boolean followRedirects() default true; - - /** - * Configure this client to retry or not when a connectivity problem is encountered. - * By default, this client silently recovers from the following problems: - * - * @return retryOnConnectionFailure + * 根据该名称从Spring容器中对应的OkHttpClient来初始化当前接口的OkHttpClient */ - boolean retryOnConnectionFailure() default true; + String baseOkHttpClientBeanName() default Constants.DEFAULT_BASE_OK_HTTP_CLIENT; } diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/core/RetrofitFactoryBean.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/core/RetrofitFactoryBean.java index 5f9c3f8..b659223 100644 --- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/core/RetrofitFactoryBean.java +++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/core/RetrofitFactoryBean.java @@ -1,9 +1,6 @@ package com.github.lianjiatech.retrofit.spring.boot.core; import java.lang.annotation.Annotation; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -11,7 +8,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.concurrent.TimeUnit; import org.springframework.beans.BeansException; import org.springframework.beans.factory.FactoryBean; @@ -25,7 +21,6 @@ import org.springframework.util.StringUtils; import com.github.lianjiatech.retrofit.spring.boot.config.RetrofitConfigBean; -import com.github.lianjiatech.retrofit.spring.boot.config.RetrofitProperties; import com.github.lianjiatech.retrofit.spring.boot.degrade.DegradeProxy; import com.github.lianjiatech.retrofit.spring.boot.degrade.RetrofitDegrade; import com.github.lianjiatech.retrofit.spring.boot.interceptor.BasePathMatchInterceptor; @@ -36,7 +31,6 @@ import com.github.lianjiatech.retrofit.spring.boot.util.BeanExtendUtils; import com.github.lianjiatech.retrofit.spring.boot.util.RetrofitUtils; -import okhttp3.ConnectionPool; import okhttp3.Interceptor; import okhttp3.OkHttpClient; import retrofit2.Retrofit; @@ -50,8 +44,6 @@ public class RetrofitFactoryBean implements FactoryBean, EnvironmentAware, private Environment environment; - private RetrofitProperties retrofitProperties; - private RetrofitConfigBean retrofitConfigBean; private ApplicationContext applicationContext; @@ -88,22 +80,12 @@ public boolean isSingleton() { return true; } - private okhttp3.ConnectionPool parseConnectionPool() { - RetrofitClient retrofitClient = - AnnotatedElementUtils.findMergedAnnotation(retrofitInterface, RetrofitClient.class); - String poolName = retrofitClient.poolName(); - Map poolRegistry = retrofitConfigBean.getPoolRegistry(); - Assert.notNull(poolRegistry, "poolRegistry does not exist! Please set retrofitConfigBean.poolRegistry!"); - ConnectionPool connectionPool = poolRegistry.get(poolName); - Assert.notNull(connectionPool, - "The connection pool corresponding to the current poolName does not exist! poolName = " + poolName); - return connectionPool; - } - - private OkHttpClient createOkHttpClient() throws IllegalAccessException, InvocationTargetException { - OkHttpClient.Builder okHttpClientBuilder = createOkHttpClientBuilder(); + private OkHttpClient createOkHttpClient() { RetrofitClient retrofitClient = AnnotatedElementUtils.findMergedAnnotation(retrofitInterface, RetrofitClient.class); + OkHttpClient baseOkHttpClient = applicationContext.getBean( + Objects.requireNonNull(retrofitClient).baseOkHttpClientBeanName(), OkHttpClient.class); + OkHttpClient.Builder okHttpClientBuilder = baseOkHttpClient.newBuilder(); if (isEnableDegrade(retrofitInterface)) { okHttpClientBuilder.addInterceptor(retrofitConfigBean.getRetrofitDegrade()); } @@ -119,48 +101,6 @@ private OkHttpClient createOkHttpClient() throws IllegalAccessException, Invocat return okHttpClientBuilder.build(); } - private OkHttpClient.Builder createOkHttpClientBuilder() throws InvocationTargetException, IllegalAccessException { - RetrofitClient retrofitClient = - AnnotatedElementUtils.findMergedAnnotation(retrofitInterface, RetrofitClient.class); - Method method = findOkHttpClientBuilderMethod(); - if (method != null) { - return (OkHttpClient.Builder)method.invoke(null); - } - okhttp3.ConnectionPool connectionPool = parseConnectionPool(); - final int connectTimeoutMs = retrofitClient.connectTimeoutMs() == -1 - ? retrofitProperties.getGlobalConnectTimeoutMs() : retrofitClient.connectTimeoutMs(); - final int readTimeoutMs = retrofitClient.readTimeoutMs() == -1 ? retrofitProperties.getGlobalReadTimeoutMs() - : retrofitClient.readTimeoutMs(); - final int writeTimeoutMs = retrofitClient.writeTimeoutMs() == -1 - ? retrofitProperties.getGlobalWriteTimeoutMs() : retrofitClient.writeTimeoutMs(); - final int callTimeoutMs = retrofitClient.callTimeoutMs() == -1 ? retrofitProperties.getGlobalCallTimeoutMs() - : retrofitClient.callTimeoutMs(); - - // Construct an OkHttpClient object - return new OkHttpClient.Builder() - .connectTimeout(connectTimeoutMs, TimeUnit.MILLISECONDS) - .readTimeout(readTimeoutMs, TimeUnit.MILLISECONDS) - .writeTimeout(writeTimeoutMs, TimeUnit.MILLISECONDS) - .callTimeout(callTimeoutMs, TimeUnit.MILLISECONDS) - .retryOnConnectionFailure(retrofitClient.retryOnConnectionFailure()) - .followRedirects(retrofitClient.followRedirects()) - .followSslRedirects(retrofitClient.followSslRedirects()) - .pingInterval(retrofitClient.pingIntervalMs(), TimeUnit.MILLISECONDS) - .connectionPool(connectionPool); - } - - private Method findOkHttpClientBuilderMethod() { - Method[] methods = retrofitInterface.getMethods(); - for (Method method : methods) { - if (Modifier.isStatic(method.getModifiers()) - && method.isAnnotationPresent(OkHttpClientBuilder.class) - && method.getReturnType().equals(OkHttpClient.Builder.class)) { - return method; - } - } - return null; - } - @SuppressWarnings("unchecked") private List findInterceptorByAnnotation() { Annotation[] classAnnotations = AnnotationUtils.getAnnotations(retrofitInterface); @@ -209,7 +149,7 @@ private List findInterceptorByAnnotation() { return interceptors; } - private Retrofit createRetrofit() throws IllegalAccessException, InvocationTargetException { + private Retrofit createRetrofit() { RetrofitClient retrofitClient = AnnotatedElementUtils.findMergedAnnotation(retrofitInterface, RetrofitClient.class); String baseUrl = RetrofitUtils.convertBaseUrl(retrofitClient, retrofitClient.baseUrl(), environment); @@ -252,6 +192,5 @@ public void setEnvironment(Environment environment) { public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; this.retrofitConfigBean = applicationContext.getBean(RetrofitConfigBean.class); - this.retrofitProperties = retrofitConfigBean.getRetrofitProperties(); } } diff --git a/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/RetrofitTestApplication.java b/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/RetrofitTestApplication.java index cedc617..84d3ab1 100644 --- a/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/RetrofitTestApplication.java +++ b/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/RetrofitTestApplication.java @@ -1,8 +1,15 @@ package com.github.lianjiatech.retrofit.spring.boot.test; +import java.util.concurrent.TimeUnit; + import org.springframework.boot.SpringApplication; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import lombok.extern.slf4j.Slf4j; +import okhttp3.ConnectionPool; +import okhttp3.Dispatcher; +import okhttp3.OkHttpClient; import retrofit2.converter.gson.GsonConverterFactory; import retrofit2.converter.jaxb.JaxbConverterFactory; @@ -10,6 +17,7 @@ * @author 陈添明 */ @MySpringBootApplication +@Slf4j public class RetrofitTestApplication { public static void main(String[] args) { @@ -25,4 +33,34 @@ GsonConverterFactory gsonConverterFactory() { JaxbConverterFactory jaxbConverterFactory() { return JaxbConverterFactory.create(); } + + @Bean + @Primary + OkHttpClient defaultBaseOkHttpClient() { + return new OkHttpClient.Builder() + .addInterceptor(chain -> { + log.info("=======替换defaultBaseOkHttpClient构建OkHttpClient====="); + return chain.proceed(chain.request()); + }) + .build(); + } + + @Bean + OkHttpClient testOkHttpClient() { + Dispatcher dispatcher = new Dispatcher(); + dispatcher.setMaxRequests(100); + dispatcher.setMaxRequestsPerHost(10); + + return new OkHttpClient.Builder() + .readTimeout(1, TimeUnit.SECONDS) + .writeTimeout(1, TimeUnit.SECONDS) + .connectTimeout(1, TimeUnit.SECONDS) + .dispatcher(dispatcher) + .connectionPool(new ConnectionPool(10, 10, TimeUnit.MINUTES)) + .addInterceptor(chain -> { + log.info("=======基于testOkHttpClient构建OkHttpClient====="); + return chain.proceed(chain.request()); + }) + .build(); + } } diff --git a/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/custom/okhttp/CustomOkHttpTest.java b/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/custom/okhttp/CustomOkHttpTest.java new file mode 100644 index 0000000..01d2fdb --- /dev/null +++ b/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/custom/okhttp/CustomOkHttpTest.java @@ -0,0 +1,78 @@ +package com.github.lianjiatech.retrofit.spring.boot.test.custom.okhttp; + +import java.io.IOException; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.github.lianjiatech.retrofit.spring.boot.test.RetrofitTestApplication; +import com.github.lianjiatech.retrofit.spring.boot.test.entity.Person; +import com.github.lianjiatech.retrofit.spring.boot.test.entity.Result; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +/** + * @author 陈添明 + */ +@SpringBootTest(classes = RetrofitTestApplication.class) +@RunWith(SpringRunner.class) +public class CustomOkHttpTest { + + @Autowired + private CustomOkHttpTestApi customOkHttpTestApi; + + private MockWebServer server; + + private static Gson gson = new GsonBuilder() + .create(); + + @Before + public void before() throws IOException { + System.out.println("=========开启MockWebServer==========="); + server = new MockWebServer(); + server.start(8080); + + } + + @After + public void after() throws IOException { + System.out.println("=========关闭MockWebServer==========="); + server.close(); + } + + @Test + public void test() { + + // mock + Person mockPerson = new Person().setId(1L) + .setName("test") + .setAge(10); + Result mockResult = new Result<>() + .setCode(0) + .setMsg("ok") + .setData(mockPerson); + MockResponse response = new MockResponse() + .setResponseCode(200) + .addHeader("Content-Type", "application/json; charset=utf-8") + .addHeader("Cache-Control", "no-cache") + .setBody(gson.toJson(mockResult)); + server.enqueue(response); + + // http check + Result person = customOkHttpTestApi.getPerson(1L); + Person data = person.getData(); + Assert.assertNotNull(data); + Assert.assertEquals("test", data.getName()); + Assert.assertEquals(10, data.getAge().intValue()); + } + +} diff --git a/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/custom/okhttp/CustomOkHttpTestApi.java b/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/custom/okhttp/CustomOkHttpTestApi.java new file mode 100644 index 0000000..7b219aa --- /dev/null +++ b/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/custom/okhttp/CustomOkHttpTestApi.java @@ -0,0 +1,23 @@ +package com.github.lianjiatech.retrofit.spring.boot.test.custom.okhttp; + +import com.github.lianjiatech.retrofit.spring.boot.core.RetrofitClient; +import com.github.lianjiatech.retrofit.spring.boot.test.entity.Person; +import com.github.lianjiatech.retrofit.spring.boot.test.entity.Result; + +import retrofit2.http.GET; +import retrofit2.http.Headers; +import retrofit2.http.Query; + +/** + * @author 陈添明 + */ +@RetrofitClient(baseUrl = "${test.baseUrl}", baseOkHttpClientBeanName = "testOkHttpClient") +public interface CustomOkHttpTestApi { + + @GET("person") + @Headers({ + "X-Foo: Bar", + "X-Ping: Pong" + }) + Result getPerson(@Query("id") Long id); +} diff --git a/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/http/HttpApi.java b/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/http/HttpApi.java index cdf9db3..0a8940a 100644 --- a/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/http/HttpApi.java +++ b/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/http/HttpApi.java @@ -22,7 +22,7 @@ /** * @author 陈添明 */ -@RetrofitClient(baseUrl = "${test.baseUrl}", poolName = "test1", errorDecoder = TestErrorDecoder.class) +@RetrofitClient(baseUrl = "${test.baseUrl}", errorDecoder = TestErrorDecoder.class) @Sign(accessKeyId = "${test.accessKeyId}", accessKeySecret = "${test.accessKeySecret}", exclude = {"/api/test/query"}) @Intercept(handler = TimeStampInterceptor.class) @Intercept(handler = TimeStamp2Interceptor.class) diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index 4627471..1afddf7 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -1,14 +1,5 @@ retrofit: - # 连接池配置 - pool: - # test1连接池配置 - test1: - # 最大空闲连接数 - max-idle-connections: 3 - # 连接保活时间(秒) - keep-alive-second: 100 - # 全局转换器工厂 global-converter-factories: - com.github.lianjiatech.retrofit.spring.boot.core.BasicTypeConverterFactory @@ -87,15 +78,6 @@ retrofit: # 启用可写堆栈跟踪的标志 writable-stack-trace-enabled: true - # 全局连接超时时间 - global-connect-timeout-ms: 5000 - # 全局读取超时时间 - global-read-timeout-ms: 5000 - # 全局写入超时时间 - global-write-timeout-ms: 5000 - # 全局完整调用超时时间 - global-call-timeout-ms: 0 - test: baseUrl: http://localhost:8080/api/test/ accessKeyId: root diff --git a/src/test/resources/default-config.yml b/src/test/resources/default-config.yml index 776c32d..f4e67e7 100644 --- a/src/test/resources/default-config.yml +++ b/src/test/resources/default-config.yml @@ -1,13 +1,4 @@ retrofit: - # 连接池配置 - pool: - # default连接池 - default: - # 最大空闲连接数 - max-idle-connections: 5 - # 连接保活时间(秒) - keep-alive-second: 300 - # 全局转换器工厂 global-converter-factories: - com.github.lianjiatech.retrofit.spring.boot.core.BasicTypeConverterFactory @@ -84,12 +75,3 @@ retrofit: slow-call-duration-threshold-seconds: 60 # 启用可写堆栈跟踪的标志 writable-stack-trace-enabled: true - - # 全局连接超时时间 - global-connect-timeout-ms: 10000 - # 全局读取超时时间 - global-read-timeout-ms: 10000 - # 全局写入超时时间 - global-write-timeout-ms: 10000 - # 全局完整调用超时时间 - global-call-timeout-ms: 0