【Java万花筒】解码Java网络通讯谜团:对比Apache HttpClient、OkHttp、Feign、RestTemplate、Retrofit

Java网络请求大比拼:HttpClient、OkHttp、Feign、RestTemplate、Retrofit全面解析

前言

在当今互联网时代,Java开发者常常需要处理与各种RESTful服务的通信。本文旨在深入比较Java中几个主流的网络请求库,包括Apache HttpClient、OkHttp、Feign、RestTemplate、Retrofit。通过全面的介绍和示例代码,读者将能够了解它们的特点、优势以及如何在实际项目中使用。

欢迎订阅专栏:Java万花筒

文章目录

  • Java网络请求大比拼:HttpClient、OkHttp、Feign、RestTemplate、Retrofit全面解析
    • 前言
      • 1. Apache HttpClient
        • 1.1 概述
          • 1.1.1 功能介绍
          • 1.1.2 应用场景
        • 1.2 使用示例
          • 1.2.1 添加依赖
          • 1.2.2 基本配置
          • 1.2.3 发送GET请求
          • 1.2.4 发送POST请求
        • 1.3 连接池管理
          • 1.3.1 添加依赖
          • 1.3.2 配置连接池
          • 1.3.3 使用连接池的HttpClient
        • 1.4 请求重试
          • 1.4.1 配置请求重试
        • 1.5 请求超时设置
          • 1.5.1 配置请求超时
      • 2. OkHttp
        • 2.1 概述
          • 2.1.1 特点与优势
          • 2.1.2 异步请求处理
        • 2.2 使用示例
          • 2.2.1 添加依赖
          • 2.2.2 创建OkHttpClient实例
          • 2.2.3 发送GET请求
          • 2.2.4 发送POST请求
        • 2.3 连接池配置
          • 2.3.1 添加依赖
          • 2.3.2 配置连接池
        • 2.4 请求拦截器
          • 2.4.1 添加请求拦截器
      • 3. Feign
        • 3.1 概述
          • 3.1.1 声明式HTTP客户端特点
          • 3.1.2 与Netflix的关联
        • 3.2 使用示例
          • 3.2.1 添加依赖
          • 3.2.2 声明Feign客户端接口
          • 3.2.3 调用远程API
          • 3.2.4 配置Feign客户端属性
        • 3.3 负载均衡与服务发现
          • 3.3.1 添加依赖
          • 3.3.2 配置负载均衡和服务发现
        • 3.4 自定义Decoder和Encoder
          • 3.4.1 自定义Decoder
          • 3.4.2 自定义Encoder
          • 3.4.3 使用自定义Decoder和Encoder
      • 4. RestTemplate
        • 4.1 概述
          • 4.1.1 Spring框架中的HTTP客户端
          • 4.1.2 与Spring Boot集成
        • 4.2 使用示例
          • 4.2.1 添加依赖
          • 4.2.2 创建RestTemplate实例
          • 4.2.3 发送GET请求
          • 4.2.4 发送POST请求
        • 4.3 自定义请求拦截器
          • 4.3.1 添加请求拦截器
          • 4.3.2 使用自定义请求拦截器
        • 4.4 异步请求
          • 4.4.1 发送异步GET请求
          • 4.4.2 发送异步POST请求
      • 5. Retrofit
        • 5.1 概述
          • 5.1.1 适用于Android平台的REST客户端
          • 5.1.2 注解驱动的API定义
        • 5.2 使用示例
          • 5.2.1 添加依赖
          • 5.2.2 定义API接口
          • 5.2.3 发起同步和异步请求
        • 5.3 自定义Converter
          • 5.3.1 自定义Converter
          • 5.3.2 使用自定义Converter
        • 5.4 RxJava支持
          • 5.4.1 添加RxJava依赖
          • 5.4.2 使用RxJava发起请求
    • 总结

1. Apache HttpClient

1.1 概述

Apache HttpClient 是一个功能强大、灵活的HTTP客户端库,用于发送HTTP请求和处理响应。它支持各种协议,如HTTP、HTTPS、FTP等,并提供了丰富的配置选项。

1.1.1 功能介绍

Apache HttpClient 提供了丰富的功能,包括连接池管理、请求重试、请求超时设置等。它是基于Java的标准库构建的,因此在Java应用程序中具有良好的集成性。

1.1.2 应用场景

Apache HttpClient 可用于与Web服务进行通信,执行HTTP GET、POST等请求,并处理响应数据。它适用于需要灵活配置和高度控制HTTP请求的场景。

1.2 使用示例
1.2.1 添加依赖
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
1.2.2 基本配置
CloseableHttpClient httpClient = HttpClients.createDefault();
1.2.3 发送GET请求
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.util.EntityUtils;HttpGet httpGet = new HttpGet("https://example.com/api/resource");
try (CloseableHttpResponse response = httpClient.execute(httpGet)) {String responseBody = EntityUtils.toString(response.getEntity());System.out.println("GET Response: " + responseBody);
}
1.2.4 发送POST请求
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;HttpPost httpPost = new HttpPost("https://example.com/api/resource");
httpPost.setEntity(new StringEntity("Request data"));try (CloseableHttpResponse response = httpClient.execute(httpPost)) {String responseBody = EntityUtils.toString(response.getEntity());System.out.println("POST Response: " + responseBody);
}
1.3 连接池管理

Apache HttpClient 提供了连接池管理的功能,通过连接池可以有效地重用HTTP连接,提高性能和减少资源消耗。下面是连接池的基本使用示例:

1.3.1 添加依赖
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
1.3.2 配置连接池
// 注册HTTP和HTTPS连接工厂
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", SSLConnectionSocketFactory.getSocketFactory()).build();// 创建连接池管理器
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
1.3.3 使用连接池的HttpClient
// 使用连接池创建HttpClient
CloseableHttpClient httpClientWithPool = HttpClients.custom().setConnectionManager(connectionManager).build();
1.4 请求重试

Apache HttpClient 支持请求的自动重试功能,可以通过配置实现。这在处理网络不稳定或临时故障时非常有用。

1.4.1 配置请求重试
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.CloseableHttpClient;// 配置请求重试次数为3次
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).build();CloseableHttpClient httpClientWithRetry = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)).build();

在上述示例中,我们通过 setRetryHandler 方法配置了请求重试处理器,并设置最大重试次数为3次。第二个参数 true 表示请求失败后将自动重试。

通过这种配置,可以增强系统的健壮性,应对在网络不稳定的环境下发生的临时故障。在实际应用中,可以根据具体情况调整最大重试次数和是否开启自动重试。

1.5 请求超时设置

Apache HttpClient 允许对请求的超时时间进行配置,以确保在一定时间内完成HTTP请求。

1.5.1 配置请求超时
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000)  // 设置读取超时时间.setConnectTimeout(5000) // 设置连接超时时间.build();CloseableHttpClient httpClientWithTimeout = HttpClients.custom().setDefaultRequestConfig(requestConfig).build();

这样,我们通过添加连接池管理、请求重试和请求超时设置的示例代码,进一步扩展了对 Apache HttpClient 的介绍。这些功能提供了更多的灵活性和控制,适应不同的网络环境和应用场景。在实际项目中,根据具体需求选择合适的配置将有助于提升系统的稳定性和性能。

2. OkHttp

2.1 概述

OkHttp 是一个现代化的HTTP客户端,适用于Android和Java应用程序。它提供了简单的API、高性能和灵活的配置选项。

2.1.1 特点与优势

OkHttp 支持连接池、自动重连、请求压缩等特性。它的异步请求处理能力使得在Android应用中使用时不会阻塞主线程。

2.1.2 异步请求处理

OkHttp 允许异步执行HTTP请求,通过回调或者Java 8 Lambda表达式处理异步结果。

2.2 使用示例
2.2.1 添加依赖
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
2.2.2 创建OkHttpClient实例
OkHttpClient okHttpClient = new OkHttpClient();
2.2.3 发送GET请求
Request request = new Request.Builder().url("https://example.com/api/resource").build();try (Response response = okHttpClient.newCall(request).execute()) {String responseBody = response.body().string();System.out.println("GET Response: " + responseBody);
}
2.2.4 发送POST请求
import okhttp3.MediaType;
import okhttp3.RequestBody;Request request = new Request.Builder().url("https://example.com/api/resource").post(RequestBody.create(MediaType.parse("application/json"), "Request data")).build();try (Response response = okHttpClient.newCall(request).execute()) {String responseBody = response.body().string();System.out.println("POST Response: " + responseBody);
}
2.3 连接池配置

OkHttp 提供了连接池配置,通过合理配置连接池可以提高请求的效率和性能。下面是连接池配置的示例:

2.3.1 添加依赖
import okhttp3.ConnectionPool;
2.3.2 配置连接池
OkHttpClient okHttpClientWithPool = new OkHttpClient.Builder().connectionPool(new ConnectionPool(5, 10, TimeUnit.MINUTES)) // 最大5个空闲连接,保持时间10分钟.build();

在上述示例中,我们通过 connectionPool 方法配置了连接池,设置了最大空闲连接数为5个,保持时间为10分钟。合理配置连接池可以减少连接的创建和销毁,提高性能。

2.4 请求拦截器

OkHttp 允许添加请求拦截器,通过拦截器可以在发送请求前或接收响应后执行额外的操作。

2.4.1 添加请求拦截器
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;// 自定义请求拦截器
Interceptor customInterceptor = new Interceptor() {@Overridepublic Response intercept(Chain chain) throws IOException {Request originalRequest = chain.request();// 添加自定义HeaderRequest newRequest = originalRequest.newBuilder().header("Custom-Header", "Custom-Value").build();return chain.proceed(newRequest);}
};OkHttpClient okHttpClientWithInterceptor = new OkHttpClient.Builder().addInterceptor(customInterceptor).build();

在上述示例中,我们创建了一个自定义的请求拦截器,用于在请求头中添加自定义的Header。通过添加拦截器,可以实现一些通用的请求处理逻辑。

这样,通过连接池配置和请求拦截器的示例代码,我们进一步扩展了对 OkHttp 的介绍。这些功能提供了更多的灵活性和定制化选项,使得 OkHttp 更适用于各种复杂的网络场景。

3. Feign

3.1 概述

Feign 是一个声明式的HTTP客户端,由Netflix开发,用于简化HTTP API调用。它允许使用注解定义API接口,然后通过代理模式实现远程服务调用。

3.1.1 声明式HTTP客户端特点

Feign 的注解风格使得定义和调用HTTP API更加简单和直观。它支持负载均衡、服务发现等特性。

3.1.2 与Netflix的关联

Feign 是Netflix开发的一部分,与Netflix的微服务框架集成得非常好,尤其适用于基于微服务架构的应用。

3.2 使用示例
3.2.1 添加依赖
import feign.Feign;
import feign.RequestLine;
import feign.Response;
3.2.2 声明Feign客户端接口
public interface ExampleClient {@RequestLine("GET /api/resource")Response getResource();
}
3.2.3 调用远程API
ExampleClient exampleClient = Feign.builder().target(ExampleClient.class, "https://example.com");Response response = exampleClient.getResource();
System.out.println("Feign GET Response: " + response.body());
3.2.4 配置Feign客户端属性
import feign.Feign.Builder;ExampleClient exampleClient = Feign.builder().options(new Builder().connectTimeout(10000).readTimeout(10000).build()).target(ExampleClient.class, "https://example.com");
3.3 负载均衡与服务发现

Feign 在微服务架构中常与负载均衡和服务发现结合使用,以提高系统的可用性和弹性。下面是负载均衡和服务发现的使用示例:

3.3.1 添加依赖
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.LoadBalancerBuilder;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList;
import feign.ribbon.LBClient;
import feign.ribbon.LBClientFactory;
import feign.ribbon.RibbonClient;
3.3.2 配置负载均衡和服务发现
// 定义服务列表
List<Server> serverList = Arrays.asList(new Server("example-service1", 8080),new Server("example-service2", 8080),// Add more servers as needed
);// 创建负载均衡器
ILoadBalancer loadBalancer = LoadBalancerBuilder.newBuilder().buildFixedServerListLoadBalancer(serverList);// 创建Feign客户端
ExampleClient exampleClientWithLB = RibbonClient.builder().lbClientFactory(new LBClientFactory.Default()).build().target(ExampleClient.class, "https://example-service");

在上述示例中,我们通过定义服务列表和创建负载均衡器,配置了Feign客户端支持负载均衡。这对于在微服务环境中调用多个实例的服务非常有用。

3.4 自定义Decoder和Encoder

Feign 允许自定义解码器(Decoder)和编码器(Encoder),以适应不同的数据格式或处理需求。下面是自定义Decoder和Encoder的示例:

3.4.1 自定义Decoder
import feign.codec.Decoder;
import feign.Response;
import feign.Util;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Collection;public class CustomDecoder implements Decoder {@Overridepublic Object decode(Response response, Type type) throws IOException {if (Collection.class.isAssignableFrom(Util.getRawType(type))) {// Custom logic for decoding collections}// Add more custom decoding logic as neededreturn null;}
}
3.4.2 自定义Encoder
import feign.codec.Encoder;
import feign.RequestTemplate;
import java.lang.reflect.Type;public class CustomEncoder implements Encoder {@Overridepublic void encode(Object object, Type bodyType, RequestTemplate template) throws Exception {// Custom logic for encoding the request}
}
3.4.3 使用自定义Decoder和Encoder
ExampleClient exampleClientWithCustomCodec = Feign.builder().decoder(new CustomDecoder()).encoder(new CustomEncoder()).target(ExampleClient.class, "https://example.com");

通过上述示例,我们介绍了如何在Feign中配置负载均衡与服务发现,并展示了如何自定义Decoder和Encoder。这些功能使得Feign更具适应性,可以满足复杂的微服务调用场景。

4. RestTemplate

4.1 概述

RestTemplate 是Spring框架中的HTTP客户端,用于简化HTTP请求的发送和响应处理。

4.1.1 Spring框架中的HTTP客户端

RestTemplate 是Spring提供的用于访问REST服务的模板类,它封装了HTTP请求、响应处理等细节。

4.1.2 与Spring Boot集成

RestTemplate 在Spring Boot中有着良好的支持,可以通过自动配置和注解轻松集成到Spring Boot应用中。

4.2 使用示例
4.2.1 添加依赖
import org.springframework.web.client.RestTemplate;
4.2.2 创建RestTemplate实例
RestTemplate restTemplate = new RestTemplate();
4.2.3 发送GET请求
String url = "https://example.com/api/resource";
String responseBody = restTemplate.getForObject(url, String.class);
System.out.println("GET Response: " + responseBody);
4.2.4 发送POST请求
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;String url = "https://example.com/api/resource";
String requestData = "Request data";// Set headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);// Create request entity with headers and data
HttpEntity<String> requestEntity = new HttpEntity<>(requestData, headers);// Send POST request
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, requestEntity, String.class);String responseBody = responseEntity.getBody();
System.out.println("POST Response: " + responseBody);
4.3 自定义请求拦截器

RestTemplate 允许添加请求拦截器,通过拦截器可以在发送请求前或接收响应后执行额外的操作。

4.3.1 添加请求拦截器
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse;// 自定义请求拦截器
public class CustomRequestInterceptor implements ClientHttpRequestInterceptor {@Overridepublic ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {// 添加自定义逻辑HttpHeaders headers = request.getHeaders();headers.add("Custom-Header", "Custom-Value");// 执行请求return execution.execute(request, body);}
}
4.3.2 使用自定义请求拦截器
RestTemplate restTemplateWithInterceptor = new RestTemplate();// 添加自定义请求拦截器
restTemplateWithInterceptor.getInterceptors().add(new CustomRequestInterceptor());// 发送请求
String urlWithInterceptor = "https://example.com/api/resource";
String responseBodyWithInterceptor = restTemplateWithInterceptor.getForObject(urlWithInterceptor, String.class);
System.out.println("GET Response with Interceptor: " + responseBodyWithInterceptor);

通过上述示例,我们展示了如何在 RestTemplate 中添加自定义请求拦截器,以实现在请求中添加自定义逻辑。这对于在发送请求前执行一些操作非常有用,例如添加自定义的请求头信息。

4.4 异步请求

RestTemplate 支持异步的 HTTP 请求,可以通过 ListenableFuture 或者 CompletableFuture 来处理异步结果。

4.4.1 发送异步GET请求
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.web.client.AsyncRestTemplate;AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate();String urlAsync = "https://example.com/api/resource";
ListenableFuture<ResponseEntity<String>> future = asyncRestTemplate.getForEntity(urlAsync, String.class);future.addCallback(responseEntity -> {String responseBodyAsync = responseEntity.getBody();System.out.println("Async GET Response: " + responseBodyAsync);
}, ex -> {System.err.println("Async GET Request Failed");
});
4.4.2 发送异步POST请求
String urlAsyncPost = "https://example.com/api/resource";
String requestDataAsync = "Request data";// Set headers
HttpHeaders headersAsync = new HttpHeaders();
headersAsync.setContentType(MediaType.APPLICATION_JSON);// Create request entity with headers and data
HttpEntity<String> requestEntityAsync = new HttpEntity<>(requestDataAsync, headersAsync);// Send asynchronous POST request
ListenableFuture<ResponseEntity<String>> futurePost = asyncRestTemplate.postForEntity(urlAsyncPost, requestEntityAsync, String.class);futurePost.addCallback(responseEntity -> {String responseBodyAsyncPost = responseEntity.getBody();System.out.println("Async POST Response: " + responseBodyAsyncPost);
}, ex -> {System.err.println("Async POST Request Failed");
});

通过以上示例,我们介绍了 RestTemplate 的一些进阶用法,包括自定义请求拦截器、异步请求等功能,以满足更复杂的 HTTP 请求场景。这些功能提供了更高级的定制和灵活性,适应不同的项目需求。

5. Retrofit

5.1 概述

Retrofit 是一个适用于Android平台的REST客户端库,它通过注解驱动的方式定义和处理HTTP请求。

5.1.1 适用于Android平台的REST客户端

Retrofit 被广泛应用于Android开发中,它提供了简单易用的API,使得与RESTful服务进行通信变得轻松。

5.1.2 注解驱动的API定义

Retrofit 使用注解来描述HTTP请求,通过接口方法上的注解定义请求方式、路径等信息,大大简化了API的定义和调用。

5.2 使用示例
5.2.1 添加依赖
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Body;
5.2.2 定义API接口
public interface ExampleService {@GET("/api/resource")Call<String> getResource();@POST("/api/resource")Call<String> postResource(@Body String requestData);
}
5.2.3 发起同步和异步请求
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://example.com").addConverterFactory(GsonConverterFactory.create()).build();ExampleService exampleService = retrofit.create(ExampleService.class);// Synchronous GET request
Call<String> callSyncGet = exampleService.getResource();
String responseBodySyncGet = callSyncGet.execute().body();
System.out.println("Retrofit GET Response (Sync): " + responseBodySyncGet);// Asynchronous POST request
Call<String> callAsyncPost = exampleService.postResource("Request data");
callAsyncPost.enqueue(new retrofit2.Callback<String>() {@Overridepublic void onResponse(Call<String> call, retrofit2.Response<String> response) {String responseBodyAsyncPost = response.body();System.out.println("Retrofit POST Response (Async): " + responseBodyAsyncPost);}@Overridepublic void onFailure(Call<String> call, Throwable t) {System.err.println("Retrofit POST Request Failed");}
});
5.3 自定义Converter

Retrofit 允许使用自定义的 Converter 来处理请求和响应的数据格式。下面是一个自定义 Converter 的示例:

5.3.1 自定义Converter
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;public class CustomConverterFactory extends Converter.Factory {public static CustomConverterFactory create() {return new CustomConverterFactory();}@Overridepublic Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {// Implement custom logic for response body conversionreturn null;}@Overridepublic Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {// Implement custom logic for request body conversionreturn null;}
}
5.3.2 使用自定义Converter
Retrofit retrofitWithCustomConverter = new Retrofit.Builder().baseUrl("https://example.com").addConverterFactory(CustomConverterFactory.create()).build();ExampleService exampleServiceWithCustomConverter = retrofitWithCustomConverter.create(ExampleService.class);

在上述示例中,我们创建了一个自定义的 ConverterFactory,并通过 addConverterFactory 方法将其添加到 Retrofit 中。通过实现自定义 Converter,可以适应不同的数据格式或处理需求。

5.4 RxJava支持

Retrofit 支持集成 RxJava,通过 RxJava 可以更方便地进行异步处理和响应式编程。下面是 RxJava 的使用示例:

5.4.1 添加RxJava依赖
import io.reactivex.Single;
5.4.2 使用RxJava发起请求
public interface ExampleRxService {@GET("/api/resource")Single<String> getResource();
}Retrofit retrofitWithRxJava = new Retrofit.Builder().baseUrl("https://example.com").addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();ExampleRxService exampleRxService = retrofitWithRxJava.create(ExampleRxService.class);// RxJava Single for GET request
Single<String> singleGet = exampleRxService.getResource();singleGet.subscribe(responseBody -> System.out.println("Retrofit RxJava GET Response: " + responseBody),throwable -> System.err.println("Retrofit RxJava GET Request Failed")
);

通过上述示例,我们展示了如何使用 Retrofit 的 RxJava 支持,通过 RxJava 可以更方便地进行异步处理和响应式编程。这对于在 Android 开发中处理异步操作非常有用。

总结

本文详细介绍了Java中几个主要的网络请求库,为读者提供了全面的了解和比较。Apache HttpClient以其功能强大、灵活的特性脱颖而出,OkHttp则展现了其现代化的HTTP客户端设计。Feign以声明式的API定义方式为读者提供了更简洁的调用方式,而RestTemplate作为Spring框架的一部分在Spring Boot中有着良好的支持。Retrofit作为适用于Android平台的REST客户端库,通过注解驱动的API定义让Android开发变得更加便捷。通过对这些库的深入比较,读者能够更好地选择适合自己项目需求的网络请求库,提升开发效率和系统性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/644478.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【华为 ICT HCIA eNSP 习题汇总】——题目集6

1、IEEE 802.11g 标准支持的最大协商速率为&#xff08;&#xff09;。 A、300Mbps B、150Mbps C、54Mbps D、1200Mbps 考点&#xff1a;无线局域网 解析&#xff1a;&#xff08;C&#xff09; IEEE 802.11系列标准如下表&#xff1a; 标准数据传输速率主要技术IEEE 802.111M…

【网站项目】医院管理系统源码(有源码)

🙊作者简介:多年一线开发工作经验,分享技术代码帮助学生学习,独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。🌹赠送计算机毕业设计600个选题excel文件,帮助大学选题。赠送开题报告模板,帮助书写开题报告。作者完整代码目录供你选择: 《Springboot网站项目…

✨JavaScript 第十二章(Symbol使用场景)

在JavaScript中&#xff0c;Symbol是ES6引入的一种新的原始数据类型&#xff0c;它代表了一个独一无二的值。这种独特性使得Symbol在某些特定场景下非常有用&#xff0c;尤其是当你需要创建一个不能与其他属性冲突的对象属性名时。 让我们来探讨一下Symbol的几个典型使用场景 …

『OpenCV-Python鼠标画笔』

OpenCV-Python教程链接&#xff1a; https://opencv-python-tutorials.readthedocs.io/ 示例一&#xff1a;图片上双击的位置绘制一个圆圈 首先创建一个鼠标事件回调函数&#xff0c;鼠标事件发生时就会被执行。鼠标事件可以是鼠标上的任何动作&#xff0c;比如左键按下&#x…

论述Python中列表、元组、字典和集合的概念

Python列表是用于存储任意数目、任意类型的数据集合&#xff0c;包含多个元素的有序连续的内存空间&#xff0c;是内置可变序列&#xff0c;或者说可以任意修改。在Python中&#xff0c;列表以方括号&#xff08;[ ]&#xff09;形式编写。 Python元组与Python列表类似&#x…

蓝桥杯官网填空题(01串的熵)

问题描述 答案提交 这是一道结果填空的题, 你只需要算出结果后提交即可。本题的结果为一 个整数, 在提交答案时只填写这个整数, 填写多余的内容将无法得分。 import java.util.*;public class Main {public static void main(String[] args) {for(double zero1;zero<2333…

[docker] Docker资源管理

一、docker资源控制 Docker通过Cgroup 来控制容器使用的资源配额&#xff0c;包括CPU、内存、磁盘三大方面&#xff0c;基本覆盖了常见的资源配额和使用量控制。Caroup 是ControlGroups的缩写&#xff0c;是Linux 内核提供的一种可以限制、记录、隔离进程组所使用的物理资源(如…

运行Navicat转储的数据库SQL文件失败

报错&#xff1a;1067 - Invalid default value for ‘publish_date’ 单独拎出来该建表语句执行&#xff0c;报错一样&#xff0c;都是默认值出错 查看该字段的设计语句 publish_date timestamp NOT NULL DEFAULT 0000-00-00 00:00:00 COMMENT 发布时间, 发现该字段的默认值…

MyBatis详解(2)-- mybatis配置文件

MyBatis详解&#xff08;2&#xff09; mybatis配置文件 mybatis配置文件 1.构建SqlSessionFactory的依据。 2.MyBatis最为核心的内容&#xff0c;对MyBatis的使用影响很大。 3.配置文件的层次顺序不能颠倒&#xff0c;一旦颠倒会出现异常。 < c o n f i g u r a t i o n…

CC工具箱使用指南:【属性读取】

一、简介 假设有1个用地图层和1个区块图层&#xff08;里面包括1-6号地块&#xff09;&#xff0c;想要通过空间关系判断图地图层里的图斑分别位于区块图层的哪个地块内。 有1种简单的方法是空间连接&#xff0c;但是空间连接有1个很大的问题。 当用地图斑不完全位于某个地块…

Figma怎么设置中文,Figma有中文版吗?

不是很多人不想用 Figma&#xff0c;真是因为纯英文界面而头疼。这就是为什么有人会到处搜索 Figma 如何设置中文这样的问题。 然后我们直接快刀斩乱麻&#xff0c;Figma 没有中文版&#xff0c;但是我们还有其他的方法&#xff1a;例如&#xff0c; Figma 添加一个插件来解决…

在Windows 10/11中如何添加打印机?这里提供详细步骤

本文介绍如何将打印机添加到Windows10/11。有线设备和无线设备的过程不同。 在Windows 10中添加打印机 将网络打印机添加到Windows 10 网络打印机通过本地网络连接,如蓝牙或Wi-Fi。连接到打印机之前,请打开打印机并将其连接到网络。 注意:你可能需要管理员的许可才能安装…

grid布局,flex布局实现类似响应式布局的效果

一. grid布局 实现代码 <!DOCTYPE html> <html lang"en"><head><style>.box {display: grid;grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); /*自动填充&#xff0c;最小宽度300px*/justify-content: space-between;gap:…

yml配置文件怎么引用pom.xml中的属性

目录 前言配置测试 前言 配置文件中的一些参数有时要用到pom文件中的属性&#xff0c;做到pom文件变配置文件中也跟着变&#xff0c;那如何才能做到呢&#xff0c;下面咱们来一起探讨学习。 配置 1.首先要在pom.xml中做如下配置&#xff0c;让maven渲染src/main/resources下配…

推荐系统算法 协同过滤算法详解(二)皮尔森相关系数

目录 前言 协同过滤算法(简称CF) 皮尔森(pearson)相关系数公式 算法介绍 算法示例1&#xff1a; 算法示例2 前言 理解吧同胞们&#xff0c;实在是没办发把wps公式复制到文章上&#xff0c;只能截图了&#xff0c;我服了&#xff01;&#xff01;&#xff01; 协同过滤算法…

“License“(美式拼写)/ “Licence“(英式拼写)基本含义相同 许可证或执照,通常用于表示某人获得的特定权限或资格。

“License” 和 “licence” 是两个拼写不同但含义相近的单词&#xff0c;它们在用法上存在一些区别&#xff0c;主要取决于所在的英语体系。 “License”&#xff08;美式拼写&#xff09;/ “Licence”&#xff08;英式拼写&#xff09;&#xff1a; 这两个词在美式英语和英式…

【进口控制器替代】基于Zynq-7020 FPGA的NI 8槽CompactRIO控制器

667 MHz双核CPU&#xff0c;512 MB DRAM&#xff0c;1 GB存储容量&#xff0c;Zynq-7020 FPGA&#xff0c;更宽工作温度范围&#xff0c;8槽CompactRIO控制器 cRIO-9068是一款坚固耐用的无风扇嵌入式控制器&#xff0c;可用于高级控制和监测应用。这款软件设计控制器搭载FPGA、…

c++的第一天

思维导图 输入一个字符串&#xff0c;计算大小写&#xff0c;数字&#xff0c;空格和其他字符 #include <array> #include <string>using namespace std;int main() {string str;cout << "请输入一串包含大写小写数字和空格的字符串:" ;getline(c…

flask_apscheduler源码分析

前言 遵循flask框架的标准的库&#xff0c;都称为flask扩展&#xff0c;flask_apscheduler是对apscheduler的扩展&#xff0c;也称为flask的扩展&#xff0c;最近使用flask_apscheduler遇到了一个job死亡的bug。现象&#xff1a;job平时是正常启动的&#xff0c;突然某个时刻全…

MODNet 剪枝再思考: 优化计算量的实验历程分享

目录 1 写在前面 2 模型分析 3 遇到问题 4 探索实验一 4.1 第一部分 4.2 第二部分 Error 1 Error 2 4.3 实验结果 ①参数量与计算量 ②模型大小 ③推理时延 5 探索实验二 5.1 LR Branch 5.2 HR Branch 5.2.1 初步分析 5.2.2 第一部分 enc2x 5.2.3 第二部分 en…