最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java按時間梯度實現(xiàn)異步回調(diào)接口的方法

 更新時間:2018年08月29日 16:59:43   作者:soinve  
這篇文章主要介紹了Java按時間梯度實現(xiàn)異步回調(diào)接口,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下

1. 背景

  在業(yè)務(wù)處理完之后,需要調(diào)用其他系統(tǒng)的接口,將相應(yīng)的處理結(jié)果通知給對方,若是同步請求,假如調(diào)用的系統(tǒng)出現(xiàn)異?;蚴清礄C等事件,會導(dǎo)致自身業(yè)務(wù)受到影響,事務(wù)會一直阻塞,數(shù)據(jù)庫連接不夠用等異?,F(xiàn)象,可以通過異步回調(diào)來防止阻塞,但異步的情況還存在一個問題,若調(diào)用一次不成功的話接下來怎么處理?這個地方就需要按時間梯度回調(diào),比如前期按10s間隔回調(diào),回調(diào)3次,若不成功按30s回調(diào),回調(diào)2次,再不成功按分鐘回調(diào),依次類推……相當(dāng)于給了對方系統(tǒng)恢復(fù)的時間,不可能一直處于異常或宕機等異常狀態(tài),若是再不成功可以再通過人工干預(yù)的手段去處理了,具體業(yè)務(wù)具體實現(xiàn)。

2. 技術(shù)實現(xiàn)

  大體實現(xiàn)思路如下圖,此過程用到兩個隊列,當(dāng)前隊列和Next隊列,當(dāng)前隊列用來存放第一次需要回調(diào)的數(shù)據(jù)對象,如果調(diào)用不成功則放入Next隊列,按照制定的時間策略再繼續(xù)回調(diào),直到成功或最終持久化后人工接入處理。

  用到的技術(shù)如下:

•http請求庫,retrofit2
•隊列,LinkedBlockingQueue
•調(diào)度線程池,ScheduledExecutorService

3. 主要代碼說明

3.1 回調(diào)時間梯度的策略設(shè)計

采用枚舉來對策略規(guī)則進行處理,便于代碼上的維護,該枚舉設(shè)計三個參數(shù),級別、回調(diào)間隔、回調(diào)次數(shù);

/**
 * 回調(diào)策略
 */
public enum CallbackType {
  //等級1,10s執(zhí)行3次
  SECONDS_10(1, 10, 3),
  //等級2,30s執(zhí)行2次
  SECONDS_30(2, 30, 2),
  //等級3,60s執(zhí)行2次
  MINUTE_1(3, 60, 2),
  //等級4,5min執(zhí)行1次
  MINUTE_5(4, 300, 1),
  //等級5,30min執(zhí)行1次
  MINUTE_30(5, 30*60, 1),
  //等級6,1h執(zhí)行2次
  HOUR_1(6, 60*60, 1),
  //等級7,3h執(zhí)行2次
  HOUR_3(7, 60*60*3, 1),
  //等級8,6h執(zhí)行2次
  HOUR_6(8, 60*60*6, 1);

  //級別
  private int level;
  //回調(diào)間隔時間 秒
  private int intervalTime;
  //回調(diào)次數(shù)
  private int count;
}

3.2 數(shù)據(jù)傳輸對象設(shè)計

聲明抽象父類,便于其他對象調(diào)用傳輸繼承。

/**
 * 消息對象父類
 */
public abstract class MessageInfo {
  //開始時間
  private long startTime;
  //更新時間
  private long updateTime;
  //是否回調(diào)成功
  private boolean isSuccess=false;
  //回調(diào)次數(shù)
  private int count=0;
  //回調(diào)策略
  private CallbackType callbackType;
}

要傳輸?shù)膶ο?,繼承消息父類;

/**
 * 工單回調(diào)信息
 */
public class WorkOrderMessage extends MessageInfo {
  //車架號
  private String vin;
  //工單號
  private String workorderno;
  //工單狀態(tài)
  private Integer status;
  //工單原因
  private String reason;
  //操作用戶
  private Integer userid;
}

3.3 調(diào)度線程池的使用

//聲明線程池,大小為16
private ScheduledExecutorService pool = Executors.newScheduledThreadPool(16);

...略

while (true){
      //從隊列獲取數(shù)據(jù),交給定時器執(zhí)行
      try {
        WorkOrderMessage message = MessageQueue.getMessageFromNext();
        long excueTime = message.getUpdateTime()+message.getCallbackType().getIntervalTime()* 1000;
        long t = excueTime - System.currentTimeMillis();
        if (t/1000 < 5) {//5s之內(nèi)將要執(zhí)行的數(shù)據(jù)提交給調(diào)度線程池
          System.out.println("MessageHandleNext-滿足定時器執(zhí)行條件"+JSONObject.toJSONString(message));
          pool.schedule(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
              remoteCallback(message);
              return true;
            }
          }, t, TimeUnit.MILLISECONDS);
        }else {
          MessageQueue.putMessageToNext(message);
        }
      } catch (InterruptedException e) {
        System.out.println(e);
      }
    }

3.4 retrofit2的使用,方便好用。

具體可查看官網(wǎng)相關(guān)文檔進行了解,用起來還是比較方便的。http://square.github.io/retrofit/

retrofit初始化:

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class RetrofitHelper {
  private static final String HTTP_URL = "http://baidu.com/";
  private static Retrofit retrofit;
  public static Retrofit instance(){
    if (retrofit == null){
      retrofit = new Retrofit.Builder()
          .baseUrl(HTTP_URL)
          .addConverterFactory(GsonConverterFactory.create())
          .build();
    }
    return retrofit;
  }
}

如果需要修改超時時間,連接時間等可以這樣初始話,Retrofit采用OkHttpClient

import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import java.util.concurrent.TimeUnit;
public class RetrofitHelper {
  private static final String HTTP_URL = "http://baidu.com/";
  private static Retrofit retrofit;
  public static Retrofit instance(){
    if (retrofit == null){
      retrofit = new Retrofit.Builder()
          .baseUrl(HTTP_URL)
          .client(new OkHttpClient.Builder()
              .connectTimeout(30, TimeUnit.SECONDS)//連接時間
              .readTimeout(30, TimeUnit.SECONDS)//讀時間
              .writeTimeout(30, TimeUnit.SECONDS)//寫時間
              .build())
          .addConverterFactory(GsonConverterFactory.create())
          .build();
    }
    return retrofit;
  }
}

Retrofit使用通過接口調(diào)用,要先聲明一個接口;

import com.alibaba.fastjson.JSONObject;
import com.woasis.callbackdemo.bean.WorkOrderMessage;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.POST;
public interface WorkOrderMessageInterface {
  @POST("/api")
  Call<JSONObject> updateBatteryInfo(@Body WorkOrderMessage message);
}

接口和實例對象準(zhǔn)備好了,接下來就是調(diào)用;

private void remoteCallback(WorkOrderMessage message){
    //實例接口對象
    WorkOrderMessageInterface workOrderMessageInterface = RetrofitHelper.instance().create(WorkOrderMessageInterface.class);
    //調(diào)用接口方法
    Call<JSONObject> objectCall = workOrderMessageInterface.updateBatteryInfo(message);
    System.out.println("遠(yuǎn)程調(diào)用執(zhí)行:"+new Date());
    //異步調(diào)用執(zhí)行
    objectCall.enqueue(new Callback<JSONObject>() {
      @Override
      public void onResponse(Call<JSONObject> call, Response<JSONObject> response) {
        System.out.println("MessageHandleNext****調(diào)用成功"+Thread.currentThread().getId());
        message.setSuccess(true);
        System.out.println("MessageHandleNext-回調(diào)成功"+JSONObject.toJSONString(message));
      }
      @Override
      public void onFailure(Call<JSONObject> call, Throwable throwable) {
        System.out.println("MessageHandleNext++++調(diào)用失敗"+Thread.currentThread().getId());
        //失敗后再將數(shù)據(jù)放入隊列
        try {
          //對回調(diào)策略初始化
          long currentTime = System.currentTimeMillis();
          message.setUpdateTime(currentTime);
          message.setSuccess(false);
          CallbackType callbackType = message.getCallbackType();
          //獲取等級
          int level = CallbackType.getLevel(callbackType);
          //獲取次數(shù)
          int count = CallbackType.getCount(callbackType);
          //如果等級已經(jīng)最高,則不再回調(diào)
          if (CallbackType.HOUR_6.getLevel() == callbackType.getLevel() && count == message.getCount()){
            System.out.println("MessageHandleNext-等級最高,不再回調(diào), 線下處理:"+JSONObject.toJSONString(message));
          }else {
            //看count是否最大,count次數(shù)最大則增加level
            if (message.getCount()<callbackType.getCount()){
              message.setCount(message.getCount()+1);
            }else {//如果不小,則增加level
              message.setCount(1);
              level += 1;
              message.setCallbackType(CallbackType.getTypeByLevel(level));
            }
            MessageQueue.putMessageToNext(message);
          }
        } catch (InterruptedException e) {
          e.printStackTrace();
          System.out.println("MessageHandleNext-放入隊列數(shù)據(jù)失敗");
        }
      }
    });
  }

3.5結(jié)果實現(xiàn)

4.總結(jié)

本次實現(xiàn)了按照時間梯度去相應(yīng)其他系統(tǒng)的接口,不再導(dǎo)致本身業(yè)務(wù)因其他系統(tǒng)的異常而阻塞。

源碼:https://github.com/liuzwei/callback-demo

以上所述是小編給大家介紹的Java按時間梯度實現(xiàn)異步回調(diào)接口,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Java中的源文件、字節(jié)碼文件解讀

    Java中的源文件、字節(jié)碼文件解讀

    這篇文章主要介紹了Java中的源文件、字節(jié)碼文件,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • Java?ArrayList集合之解鎖數(shù)據(jù)存儲新姿勢

    Java?ArrayList集合之解鎖數(shù)據(jù)存儲新姿勢

    這篇文章主要介紹了Java?ArrayList集合之解鎖數(shù)據(jù)存儲新姿勢,ArrayList是一個動態(tài)數(shù)組,可以自動調(diào)整大小,并提供了豐富的操作方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-03-03
  • mybatis使用xml進行增刪改查代碼解析

    mybatis使用xml進行增刪改查代碼解析

    這篇文章主要介紹了mybatis使用xml進行增刪改查代碼解析,分享了相關(guān)配置和代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下
    2018-02-02
  • Java實現(xiàn)有限狀態(tài)機的推薦方案分享

    Java實現(xiàn)有限狀態(tài)機的推薦方案分享

    有限狀態(tài)機又稱有限狀態(tài)自動機,簡稱狀態(tài)機,是表示有限個狀態(tài)以及在這些狀態(tài)之間的轉(zhuǎn)移和動作等行為的數(shù)學(xué)模型,這篇文章主要給大家介紹了關(guān)于Java實現(xiàn)有限狀態(tài)機的推薦方案,需要的朋友可以參考下
    2021-11-11
  • Java?Io?File文件操作基礎(chǔ)教程

    Java?Io?File文件操作基礎(chǔ)教程

    這篇文章主要介紹了Java?Io?File文件操作,在這里需要注意File只能訪問文件以及文件系統(tǒng)的元數(shù)據(jù)。如果你想讀寫文件內(nèi)容,需要使用FileInputStream、FileOutputStream或者RandomAccessFile,需要的朋友可以參考下
    2022-05-05
  • 前端如何調(diào)用后端接口進行數(shù)據(jù)交互詳解(axios和SpringBoot)

    前端如何調(diào)用后端接口進行數(shù)據(jù)交互詳解(axios和SpringBoot)

    一般來講前端不會給后端接口,而是后端給前端接口的情況比較普遍,下面這篇文章主要給大家介紹了關(guān)于前端如何調(diào)用后端接口進行數(shù)據(jù)交互的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-03-03
  • springboot 緩存@EnableCaching實例

    springboot 緩存@EnableCaching實例

    這篇文章主要介紹了springboot 緩存@EnableCaching實例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • MyBatis3源碼解析之如何獲取數(shù)據(jù)源詳解

    MyBatis3源碼解析之如何獲取數(shù)據(jù)源詳解

    用myBatis3與spring整合的時候,我們可以通過多種方式獲取數(shù)據(jù)源,下面這篇文章主要給大家介紹了關(guān)于MyBatis3源碼解析之如何獲取數(shù)據(jù)源的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • Java過濾XSS腳本攻擊詳細(xì)代碼示例

    Java過濾XSS腳本攻擊詳細(xì)代碼示例

    這篇文章主要介紹了Java過濾XSS腳本攻擊的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • java操作excel導(dǎo)入導(dǎo)出的3種方式

    java操作excel導(dǎo)入導(dǎo)出的3種方式

    項目需要,要實現(xiàn)一個導(dǎo)入導(dǎo)出excel的功能,于是任務(wù)驅(qū)動著我學(xué)習(xí)到了POI、easypoi和easyexcel這3個java操作Excel的工具,下面這篇文章主要給大家介紹了關(guān)于java操作excel導(dǎo)入導(dǎo)出的3種方式,需要的朋友可以參考下
    2023-05-05

最新評論

镇平县| 晋宁县| 德安县| 巩留县| 嘉禾县| 江川县| 军事| 博爱县| 盐源县| 萝北县| 大悟县| 威远县| 庄浪县| 华阴市| 石阡县| 扶绥县| 定襄县| 房产| 大邑县| 宜良县| 博客| 治县。| 房产| 余姚市| 东丽区| 丁青县| 平阴县| 永年县| 水富县| 灵宝市| 诸城市| 南召县| 内丘县| 隆德县| 舟山市| 于田县| 孝昌县| 天镇县| 九龙城区| 花垣县| 聊城市|