Java学习之RPC常用工具Retrofit使用样例

  • Post author:
  • Post category:java

Retrofit简介

  • 概念

    Retrofit是Square开源的一款基于OkHttp封装的网络请求框架,主要的网络请求还是OkHttp来完成,Retrofit只是对OkHttp进行了封装。

    retrofit简介

Retrofit实战

  • 使用步骤

    1. 添加Retrofit库的依赖
    2. 创建 接收服务器返回数据 的类
    3. 创建 用于描述网络请求 的接口
    4. 创建 Retrofit 实例
    5. 创建 网络请求接口实例 并 配置网络请求参数
    6. 发送网络请求(封装了 数据转换、线程切换的操作)
    7. 处理服务器返回的数据

添加依赖

  • pom

    
        <dependency>
            <groupId>com.squareup.retrofit2</groupId>
            <artifactId>retrofit</artifactId>
            <version>2.5.0</version>
        </dependency>
        <!-- 返回数据转换器依赖(例如的是String 就需要 scalar,如果是 json,需要使用 gson 等) -->
        <dependency>
            <groupId>com.squareup.retrofit2</groupId>
            <artifactId>converter-scalars</artifactId>
            <version>2.5.0</version>
            <scope>test</scope>
        </dependency>
        <!-- RxJava 其实和 Retrofit关系不大,流式编程的思想,丰富的操作符,线程的任意切换等优点 -->
        <dependency>
            <groupId>com.squareup.retrofit2</groupId>
            <artifactId>adapter-rxjava2</artifactId>
            <version>2.3.0</version>
            <scope>test</scope>
        </dependency>
    
    
    
    

创建 用于描述网络请求 的接口

  • 内容介绍

    Retrofit将 Http请求 抽象成 Java接口:采用 注解 描述网络请求参数 和 配置网络请求参数

  • 流程说明

    用 动态代理 动态 将该接口的注解“翻译”成一个 Http 请求,最后再执行 Http 请求

    注:接口中的每个方法的参数都需要使用注解标注,否则会报错。

  • 案例源码

    
        import io.reactivex.Single;
        import okhttp3.ResponseBody;
        import retrofit2.Call;
        import retrofit2.http.GET;
    
        public interface RetrofitService {
    
            // @GET注解的作用:采用Get方法发送网络请求
            // greeting() = 接收网络请求数据的方法
            // 其中返回类型为Call<*>,*是接收数据的类
            @GET("greeting")
            Call<String> greeting();
    
            @GET("delegated")
            Single<String> delegated();
    
            // 如果想直接获得Responsebody中的内容,可以定义网络请求返回值为Call<ResponseBody>
            @GET("greetingsResponse")
            Call<ResponseBody> greetingsResponse();
    
            @GET("robot/index")
            Call<String> getString(@Query("info") String info, @Query("key") String key);
        }
    
    

创建 Retrofit 实例

  • 案例源码

    
        final long TIMEOUT = 1500; // ms
        OkHttpClient client =
            new OkHttpClient.Builder()
                .connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
                .readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
                .writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
                .build();
    
        Retrofit retrofit = new Retrofit.Builder()
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 支持RxJava平台
            .addConverterFactory(ScalarsConverterFactory.create()) // 设置数据解析器
            .baseUrl("http://op.juhe.cn/") // 设置网络请求的Url地址
            .client(client)
            .build();
    
    
    

创建 网络请求接口实例

  • 案例源码

    
    
        // 创建 网络请求接口 的实例
        RetrofitService service = retrofit.create(RetrofitService.class);
    
        //对 发送请求 进行封装
        Call<String> call = service.getString("你好", "2833a660902644508778b5dfd452c080");
    
    
    
    
    

发送网络请求(异步/同步)

  • 案例源码

    
    
    
        //发送网络请求(异步)
        call.enqueue(new Callback<String>() {
            //请求成功时回调
            @Override
            public void onResponse(Call<String> call, Response<String> response) {
                //请求处理,输出结果
                response.body().show();
            }
    
            //请求失败时候的回调
            @Override
            public void onFailure(Call<String> call, Throwable throwable) {
                System.out.println("连接失败");
            }
        });
    
    
        // 发送网络请求(同步)
        Response<String> response = call.execute();
    
    
    
    
    

处理返回数据

  • 案例源码

    
    
        // 对返回数据进行处理
        response.body().show();
    
    
    

Retrofit进阶

  • 内容介绍

    熔断器适配Retrofit,添加熔断功能。

DecoratedCall

  • 内容介绍

    用于实现并装饰Retrofit的Call接口

  • 案例源码

    
        import java.io.IOException;
        import okhttp3.Request;
        import retrofit2.Call;
        import retrofit2.Callback;
        import retrofit2.Response;
    
        /**
        * Simple decorator class that implements Call&lt;T&gt; and delegates all calls the the Call
        * instance provided in the constructor. Methods can be overridden as required.
        *
        * @param <T> Call parameter type
        */
        public abstract class DecoratedCall<T> implements Call<T> {
    
            private final Call<T> call;
    
            public DecoratedCall(Call<T> call) {
                this.call = call;
            }
    
            @Override
            public Response<T> execute() throws IOException {
                return this.call.execute();
            }
    
            @Override
            public void enqueue(Callback<T> callback) {
                call.enqueue(callback);
            }
    
            @Override
            public boolean isExecuted() {
                return call.isExecuted();
            }
    
            @Override
            public void cancel() {
                call.cancel();
            }
    
            @Override
            public boolean isCanceled() {
                return call.isCanceled();
            }
    
            @Override
            public abstract Call<T> clone();
    
            @Override
            public Request request() {
                return call.request();
            }
        }
    
    
    
    

RetrofitCircuitBreaker

  • 内容介绍

    用于装饰改造Retrofit的Call,并在发生异常时通知熔断器

  • 案例源码

    
        import io.github.resilience4j.circuitbreaker.CallNotPermittedException;
        import io.github.resilience4j.circuitbreaker.CircuitBreaker;
        import io.github.resilience4j.core.StopWatch;
        import io.github.resilience4j.retrofit.internal.DecoratedCall;
        import retrofit2.Call;
        import retrofit2.Callback;
        import retrofit2.Response;
    
        import java.io.IOException;
        import java.util.concurrent.TimeUnit;
        import java.util.function.Predicate;
    
        /**
        * Decorates a Retrofit {@link Call} to inform a {@link CircuitBreaker} when an exception is thrown.
        * All exceptions are marked as errors or responses not matching the supplied predicate.  For
        * example:
        * <p>
        * <code>
        * RetrofitCircuitBreaker.decorateCall(circuitBreaker, call, Response::isSuccessful);
        * </code>
        */
        public interface RetrofitCircuitBreaker {
    
            /**
            * Decorate {@link Call}s allow {@link CircuitBreaker} functionality.
            *
            * @param circuitBreaker  {@link CircuitBreaker} to apply
            * @param call            Call to decorate
            * @param responseSuccess determines whether the response should be considered an expected
            *                        response
            * @param <T>             Response type of call
            * @return Original Call decorated with CircuitBreaker
            */
            static <T> Call<T> decorateCall(final CircuitBreaker circuitBreaker, final Call<T> call,
                final Predicate<Response> responseSuccess) {
                return new CircuitBreakingCall<>(call, circuitBreaker, responseSuccess);
            }
    
            class CircuitBreakingCall<T> extends DecoratedCall<T> {
    
                private final Call<T> call;
                private final CircuitBreaker circuitBreaker;
                private final Predicate<Response> responseSuccess;
    
                public CircuitBreakingCall(Call<T> call, CircuitBreaker circuitBreaker,
                    Predicate<Response> responseSuccess) {
                    super(call);
                    this.call = call;
                    this.circuitBreaker = circuitBreaker;
                    this.responseSuccess = responseSuccess;
                }
    
                @Override
                public void enqueue(final Callback<T> callback) {
                    try {
                        circuitBreaker.acquirePermission();
                    } catch (CallNotPermittedException cb) {
                        callback.onFailure(call, cb);
                        return;
                    }
    
                    final long start = System.nanoTime();
                    call.enqueue(new Callback<T>() {
                        @Override
                        public void onResponse(final Call<T> call, final Response<T> response) {
                            if (responseSuccess.test(response)) {
                                circuitBreaker.onResult(System.nanoTime() - start, TimeUnit.NANOSECONDS, response);
                            } else {
                                final Throwable throwable = new Throwable(
                                    "Response error: HTTP " + response.code() + " - " + response.message());
                                circuitBreaker
                                    .onError(System.nanoTime() - start, TimeUnit.NANOSECONDS, throwable);
                            }
                            callback.onResponse(call, response);
                        }
    
                        @Override
                        public void onFailure(final Call<T> call, final Throwable t) {
                            if (call.isCanceled()) {
                                circuitBreaker.releasePermission();
                            } else {
                                circuitBreaker.onError(System.nanoTime() - start, TimeUnit.NANOSECONDS, t);
                            }
                            callback.onFailure(call, t);
                        }
                    });
                }
    
                @Override
                public Response<T> execute() throws IOException {
                    circuitBreaker.acquirePermission();
                    final StopWatch stopWatch = StopWatch.start();
                    try {
                        final Response<T> response = call.execute();
    
                        if (responseSuccess.test(response)) {
                            circuitBreaker.onResult(stopWatch.stop().toNanos(), TimeUnit.NANOSECONDS, response);
                        } else {
                            final Throwable throwable = new Throwable(
                                "Response error: HTTP " + response.code() + " - " + response.message());
                            circuitBreaker
                                .onError(stopWatch.stop().toNanos(), TimeUnit.NANOSECONDS, throwable);
                        }
    
                        return response;
                    } catch (Exception exception) {
                        if (call.isCanceled()) {
                            circuitBreaker.releasePermission();
                        } else {
                            circuitBreaker
                                .onError(stopWatch.stop().toNanos(), TimeUnit.NANOSECONDS, exception);
                        }
                        throw exception;
                    }
                }
    
                @Override
                public Call<T> clone() {
                    return new CircuitBreakingCall<>(call.clone(), circuitBreaker, responseSuccess);
                }
            }
        }
    
    
    
    

CircuitBreakerCallAdapter

  • 内容介绍

    用于提供集成了熔断器的Call

  • 案例源码

    
        import io.github.resilience4j.circuitbreaker.CircuitBreaker;
        import retrofit2.Call;
        import retrofit2.CallAdapter;
        import retrofit2.Response;
        import retrofit2.Retrofit;
    
        import java.lang.annotation.Annotation;
        import java.lang.reflect.Type;
        import java.util.function.Predicate;
    
        /**
        * Creates a Retrofit {@link CallAdapter.Factory} that decorates a Call to provide integration with
        * a {@link CircuitBreaker}
        */
        public final class CircuitBreakerCallAdapter extends CallAdapter.Factory {
    
            private final CircuitBreaker circuitBreaker;
            private final Predicate<Response> successResponse;
    
            private CircuitBreakerCallAdapter(final CircuitBreaker circuitBreaker,
                final Predicate<Response> successResponse) {
                this.circuitBreaker = circuitBreaker;
                this.successResponse = successResponse;
            }
    
            /**
            * Create a circuit-breaking call adapter that decorates retrofit calls
            *
            * @param circuitBreaker circuit breaker to use
            * @return a {@link CallAdapter.Factory} that can be passed into the {@link Retrofit.Builder}
            */
            public static CircuitBreakerCallAdapter of(final CircuitBreaker circuitBreaker) {
                return of(circuitBreaker, Response::isSuccessful);
            }
    
            /**
            * Create a circuit-breaking call adapter that decorates retrofit calls
            *
            * @param circuitBreaker  circuit breaker to use
            * @param successResponse {@link Predicate} that determines whether the {@link Call} {@link
            *                        Response} should be considered successful
            * @return a {@link CallAdapter.Factory} that can be passed into the {@link Retrofit.Builder}
            */
            public static CircuitBreakerCallAdapter of(final CircuitBreaker circuitBreaker,
                final Predicate<Response> successResponse) {
                return new CircuitBreakerCallAdapter(circuitBreaker, successResponse);
            }
    
            @Override
            public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
                @SuppressWarnings("unchecked")
                CallAdapter<Object, Object> nextAdapter = (CallAdapter<Object, Object>) retrofit
                    .nextCallAdapter(this, returnType, annotations);
    
                return new CallAdapter<Object, Object>() {
                    @Override
                    public Type responseType() {
                        return nextAdapter.responseType();
                    }
    
                    @Override
                    public Object adapt(Call<Object> call) {
                        return nextAdapter.adapt(
                            RetrofitCircuitBreaker.decorateCall(circuitBreaker, call, successResponse));
                    }
                };
            }
        }
    
    
    

使用样例

  • 案例源码

    
    
        // Create a CircuitBreaker
        private final CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("testName");
    
        // Create a retrofit instance with CircuitBreaker call adapter
        Retrofit retrofit = new Retrofit.Builder()
                        .addCallAdapterFactory(CircuitBreakerCallAdapter.of(circuitBreaker))
                        .baseUrl("http://localhost:8080/")
                        .build();
    
        // Get an instance of your service with circuit breaking built-in.
        RetrofitService service = retrofit.create(RetrofitService.class);
    
    
    
    

参考链接


版权声明:本文为weixin_42586723原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。