国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Springboot自定義重試注解@Retryable

開發(fā) 架構(gòu)
新增重試任務成功之后,我們可通過調(diào)度平臺(比如:xxlJob),定時查詢重試任務表,然后調(diào)用RetryTaskDefinitionEnum中定義的重試的Service(retryServiceName),這里可以定義一個模板方法,根據(jù)RetryServiceName,從spring中獲取到對應的Bean,執(zhí)行具體的業(yè)務方法,然后更新任務狀態(tài)和重試次數(shù)即可。

一、概述

微服務之間相互調(diào)用,難免會出現(xiàn)形形色色的異常,出現(xiàn)異常時有些情況可能需要先落重試任務表,然后通過任務調(diào)度等進行定時重試;通過自定義重試注解@Retryable,減少對核心業(yè)務代碼入侵,增強代碼可讀性、可維護性。下面通過實戰(zhàn),開發(fā)自定義重試注解@Retryable。諸位可根據(jù)業(yè)務需要,稍作改造直接使用;如果有疑問、或者好的想法,歡迎留言,經(jīng)驗共享。

二、實戰(zhàn)

重試任務表定義(retry_task):

CREATE TABLE `retry_task` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵值',
  `business_type_code` varchar(32) COLLATE NOT NULL DEFAULT '' COMMENT '業(yè)務類型編碼',
  `business_type_desc` varchar(100) COLLATE NOT NULL DEFAULT '' COMMENT '業(yè)務類型描述',
  `retry_service_name` varchar(100) COLLATE NOT NULL DEFAULT '' COMMENT '重試的service名稱',
  `business_param` text COLLATE NOT NULL DEFAULT '' COMMENT '業(yè)務參數(shù)',
  `wait_retry_times` int(11) NOT NULL DEFAULT 3 COMMENT '待重試次數(shù)',
  `already_retry_times` int(11) NOT NULL DEFAULT 0 COMMENT '已重試次數(shù)',
  `retry_result_code` varchar(36) COLLATE NOT NULL DEFAULT '' COMMENT '重試結(jié)果碼',
  `retry_result_msg` varchar(255) COLLATE NOT NULL DEFAULT '' COMMENT '重試結(jié)果描述',
  `create_user` varchar(36) COLLATE NOT NULL DEFAULT '' COMMENT '創(chuàng)建人',
  `create_time` datetime NOT NULL COMMENT '創(chuàng)建時間',
  `update_user` varchar(36) COLLATE NOT NULL DEFAULT '' COMMENT '更新人',
  `update_time` datetime NOT NULL COMMENT '更新時間',
  PRIMARY KEY (`id`),
  KEY `idx_create_time` (`create_time`),
  KEY `idx_business_type_code` (`business_type_code`)
) COMMENT='重試任務表';

重試任務表實體類(RetryTaskEntity):

@Data
public class RetryTaskEntity implements Serializable {

    private static final long serialVersionUID = -1950778520234119369L;

    /**
     * 主鍵值
     */
    private BigInteger id;

    /**
     * 業(yè)務類型編碼
     */
    private String businessTypeCode;

    /**
     * 業(yè)務類型描述
     */
    private String businessTypeDesc;

    /**
     * 重試的service名稱
     */
    private String retryServiceName;

    /**
     * 業(yè)務參數(shù)
     */
    private String businessParam;

    /**
     * 待重試的次數(shù)
     */
    private Integer waitRetryTimes;

    /**
     * 已重試的次數(shù)
     */
    private Integer alreadyRetryTimes;

    /**
     * 重試結(jié)果碼
     */
    private String retryResultCode;

    /**
     * 重試結(jié)果描述
     */
    private String retryResultMsg;

    /**
     * 創(chuàng)建人
     */
    private String createUser;

    /**
     * 創(chuàng)建時間
     */
    private Date createTime;

    /**
     * 更新人
     */
    private String updateUser;

    /**
     * 更新時間
     */
    private Date updateTime;
}

重試任務表mapper和對應的xml文件:

public interface RetryTaskMapper {
    int addRetryTask(RetryTaskEntity retryTaskEntity);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.boot.demo.mapper.RetryTaskMapper">

    <insert id="addRetryTask" parameterType="com.boot.demo.pojo.RetryTaskEntity">
        INSERT INTO retry_task(business_type_code,
                               business_type_desc,
                               retry_service_name,
                               business_param,
                               wait_retry_times,
                               already_retry_times,
                               retry_result_code,
                               retry_result_msg,
                               create_user,
                               create_time,
                               update_user,
                               update_time)
        VALUES (#{businessTypeCode},
                #{businessTypeDesc},
                #{retryServiceName},
                #{businessParam},
                #{waitRetryTimes},
                #{alreadyRetryTimes},
                #{retryResultCode},
                #{retryResultMsg},
                #{createUser},
                #{createTime},
                #{updateUser},
                #{updateTime})
    </insert>
</mapper>

重試任務表service和對應的serviceImpl:

public interface RetryTaskService {
    void addRetryTask(RetryTaskEntity retryTaskEntity);
}
@Service
public class RetryTaskServiceImpl implements RetryTaskService {

    @Autowired
    private RetryTaskMapper retryTaskMapper;

    @Override
    public void addRetryTask(RetryTaskEntity retryTaskEntity) {
        retryTaskMapper.addRetryTask(retryTaskEntity);
    }
}

業(yè)務類型枚舉類(RetryTaskDefinitionEnum):

/**
 * 重試任務枚舉
 */
public enum RetryTaskDefinitionEnum {

    ADD_STOCK("101", "采購入庫成功后新增庫存異常重試", "purchaseService", 3);

    /**
     * 業(yè)務類型編碼
     */
    private final String businessTypeCode;

    /**
     * 業(yè)務類型描述
     */
    private final String businessTypeDesc;

    /**
     * 重試的service名稱
     */
    private final String retryServiceName;

    /**
     * 重試次數(shù)
     */
    private final Integer retryTimes;

    RetryTaskDefinitionEnum(String businessTypeCode, String businessTypeDesc, String retryServiceName, Integer retryTimes) {
        this.businessTypeCode = businessTypeCode;
        this.businessTypeDesc = businessTypeDesc;
        this.retryServiceName = retryServiceName;
        this.retryTimes = retryTimes;
    }

    public static RetryTaskDefinitionEnum getTaskDefinitionByBusinessTypeCode(String businessTypeCode) {
        if (StringUtils.isBlank(businessTypeCode)) {
            return null;
        }
        for (RetryTaskDefinitionEnum taskDefinition : values()) {
            if (taskDefinition.getBusinessTypeCode().equals(businessTypeCode)) {
                return taskDefinition;
            }
        }
        return null;
    }

    public String getBusinessTypeCode() {
        return businessTypeCode;
    }

    public String getBusinessTypeDesc() {
        return businessTypeDesc;
    }

    public String getRetryServiceName() {
        return retryServiceName;
    }

    public Integer getRetryTimes() {
        return retryTimes;
    }
}

自定義注解(@MyRetryable):

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
@Documented
public @interface MyRetryable {
    RetryTaskDefinitionEnum businessType();
}

自定義注解切面(MyRetryableAspect):

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import com.boot.demo.result.Result;
import com.boot.demo.result.ResultCode;
import com.boot.demo.pojo.RetryTaskEntity;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import com.boot.demo.annotation.MyRetryable;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.ProceedingJoinPoint;
import com.boot.demo.service.RetryTaskService;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import com.boot.demo.annotation.RetryTaskDefinitionEnum;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Date;

@Slf4j
@Aspect
@Component
public class MyRetryableAspect {

    @Autowired
    private RetryTaskService retryTaskService;

    @Pointcut("@annotation(com.boot.demo.annotation.MyRetryable)")
    public void pointCut() {
    }

    @Around(value = "pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) {
        Result result = null;
        try {
            // 執(zhí)行目標方法
            result = (Result) joinPoint.proceed();
            // 目標方法返回:成功結(jié)果碼(200),則無需重試
            if (ResultCode.SUCCESS.getCode() == result.getCode()) {
                return result;
            }
            // 目標方法返回:非成功結(jié)果碼(非200)則需重試(此次可根據(jù)需要判斷什么樣的返回碼需要重試)
            dealAddRetryTask(joinPoint);,
            return result;
        } catch (Throwable e) {
            log.error("myRetryableAspectLog error param: {} result: {} e: ", joinPoint.getArgs(), result, e);
            // 此處捕獲異常之后,也可以根據(jù)需要重試,這里就僅輸出異常日志
            return result;
        }
    }

    private void dealAddRetryTask(ProceedingJoinPoint joinPoint) {
        // 獲取重試注解信息
        MyRetryable myRetryableAnnotation = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(MyRetryable.class);
        if (null == myRetryableAnnotation) {
            return;
        }
        // 根據(jù)業(yè)務類型編碼,獲取枚舉中定義的業(yè)務類型描述、重試的service、重試次數(shù)等信息
        String businessTypeCode = myRetryableAnnotation.businessType().getBusinessTypeCode();
        RetryTaskDefinitionEnum retryTaskDefinition = RetryTaskDefinitionEnum.getTaskDefinitionByBusinessTypeCode(businessTypeCode);
        if (null == retryTaskDefinition) {
            return;
        }
        RetryTaskEntity retryTaskEntity = new RetryTaskEntity();
        retryTaskEntity.setBusinessTypeCode(businessTypeCode);
        retryTaskEntity.setBusinessTypeDesc(retryTaskDefinition.getBusinessTypeDesc());
        retryTaskEntity.setRetryServiceName(retryTaskDefinition.getRetryServiceName());
        retryTaskEntity.setBusinessParam(JSON.toJSONString(joinPoint.getArgs()[0]));
        retryTaskEntity.setWaitRetryTimes(retryTaskDefinition.getRetryTimes());
        retryTaskEntity.setAlreadyRetryTimes(0);
        retryTaskEntity.setRetryResultCode("");
        retryTaskEntity.setRetryResultMsg("");
        retryTaskEntity.setCreateUser("SYS");
        retryTaskEntity.setCreateTime(new Date());
        retryTaskEntity.setUpdateUser("SYS");
        retryTaskEntity.setUpdateTime(new Date());
        retryTaskService.addRetryTask(retryTaskEntity);
    }
}

基礎(chǔ)類(Result、ResultCode、ResultGenerator)。

Result類:

public class Result {

    private int code;
    private String message;
    private Object data;

    public Result setCode(ResultCode resultCode) {
        this.code = resultCode.getCode();
        return this;
    }

    public int getCode() {
        return code;
    }

    public Result setCode(int code) {
        this.code = code;
        return this;
    }

    public String getMessage() {
        return message;
    }

    public Result setMessage(String message) {
        this.message = message;
        return this;
    }

    public Object getData() {
        return data;
    }

    public Result setData(Object data) {
        this.data = data;
        return this;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Result{");
        sb.append("code=").append(code);
        sb.append(", message='").append(message).append('\'');
        sb.append(", data=").append(data);
        sb.append('}');
        return sb.toString();
    }
}

ResultCode類:

public enum ResultCode {

    SUCCESS(200),
    FAIL(400),
    UNAUTHORIZED(401),
    FORBIDDEN(403),
    NOT_FOUND(404),
    INTERNAL_SERVER_ERROR(500);

    private final int code;

    ResultCode(int code) {
        this.code = code;
    }

    public int getCode() {
        return code;
    }
}

ResultGenerator類:

public class ResultGenerator {

    private static final String DEFAULT_SUCCESS_MESSAGE = "SUCCESS";

    private ResultGenerator() {

    }

    public static Result genSuccessResult() {
        return new Result().setCode(ResultCode.SUCCESS).setMessage(DEFAULT_SUCCESS_MESSAGE);
    }

    public static Result genSuccessResult(Object data) {
        return new Result().setCode(ResultCode.SUCCESS).setMessage(DEFAULT_SUCCESS_MESSAGE).setData(data);
    }

    public static Result genFailResult(String message) {
        return new Result().setCode(ResultCode.FAIL).setMessage(message);
    }

    public static Result genFailResult(ResultCode code, String message) {
        return new Result().setCode(code).setMessage(message);
    }

    public static Result genFailResult(String message, Object data) {
        return new Result().setCode(ResultCode.FAIL).setMessage(message).setData(data);
    }
}

測試controller(PurchaseController):

@RestController
@RequestMapping("/purchase")
public class PurchaseController {

    @Autowired
    private PurchaseService purchaseService;

    @GetMapping("/test")
    public String test(String param) {
        purchaseService.addStock(param);
        return "success";
    }
}

測試PurchaseService、和PurchaseServiceImpl

public interface PurchaseService {
    Result addStock(String param);
}
@Service("purchaseService")
public class PurchaseServiceImpl implements PurchaseService {

    @Override
    // 在需要重試的業(yè)務方法上新增重試注解即可
    @MyRetryable(businessType = RetryTaskDefinitionEnum.ADD_STOCK)
    public Result addStock(String param) {
//     return ResultGenerator.genSuccessResult();
        return ResultGenerator.genFailResult("系統(tǒng)異常...");
    }
}

三、總結(jié)

新增重試任務成功之后,我們可通過調(diào)度平臺(比如:xxlJob),定時查詢重試任務表,然后調(diào)用RetryTaskDefinitionEnum中定義的重試的service(retryServiceName),這里可以定義一個模板方法,根據(jù)retryServiceName,從spring中獲取到對應的bean,執(zhí)行具體的業(yè)務方法,然后更新任務狀態(tài)和重試次數(shù)即可。

責任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2021-02-20 11:40:35

SpringBoot占位符開發(fā)技術(shù)

2024-07-02 11:42:53

SpringRedis自定義

2024-10-09 10:46:41

springboot緩存redis

2023-10-09 07:37:01

2024-10-14 17:18:27

2023-10-24 13:48:50

自定義注解舉值驗證

2024-12-27 15:37:23

2021-12-30 12:30:01

Java注解編譯器

2021-05-06 07:47:48

TestNGListener用例失敗重試

2022-11-01 11:15:56

接口策略模式

2022-02-17 07:10:39

Nest自定義注解

2020-11-25 11:20:44

Spring注解Java

2017-08-03 17:00:54

Springmvc任務執(zhí)行器

2023-07-03 08:29:11

BannerSpringBoot

2023-03-30 16:16:00

Java自定義注解開發(fā)

2015-02-12 15:33:43

微信SDK

2020-09-04 13:30:43

Java自定義代碼

2021-09-26 05:02:00

緩存Ehcache用法

2022-07-11 10:37:41

MapPart集合

2021-03-16 10:39:29

SpringBoot參數(shù)解析器
點贊
收藏

51CTO技術(shù)棧公眾號

都市激情亚洲综合| 中文av字幕一区| 精品少妇在线视频| jiyouzz国产精品久久| 天堂社区 天堂综合网 天堂资源最新版 | 亚洲激情自拍视频| 在线视频资源站| 欧美精品久久久久| 图片区亚洲欧美小说区| 欧美xxxx做受欧美| 可以免费看污视频的网站在线| 91精品福利在线一区二区三区 | 色噜噜色狠狠狠狠狠综合色一| 亚洲欧美一区二区三区极速播放 | 亚洲天堂网站| 国产成人av网址| 久久综合九色综合欧美98| 日韩精品专区| 国产精品三级美女白浆呻吟 | 国产特级毛片| 日韩欧美大尺度| 精品国产导航| 国产精美视频| 五月激情综合网| 日韩在线理论| 米仓穗香在线观看| 日韩精品中文在线观看| 欧美日韩日本国产亚洲在线| 久久国产一区| 91麻豆国产在线观看| 日本在线免费看| 国产精品高潮呻吟久久av野狼| 在线成人黄色| 成人在线高清免费| 成人a视频在线观看| 久草在线看片| 一区二区三区动漫| 蜜桃av一区二区在线观看| 欧美激情欧美狂野欧美精品| 亚洲91中文字幕无线码三区| 国产自摸综合网| 一区二区三区产品免费精品久久75| 玖玖精品一区| 激情内射人妻1区2区3区| 亚洲系列中文字幕| 国产一区二区不卡在线| 在线观看a级片| av一区二区在线看| 国产精品福利一区二区| 亚洲国内自拍| 国产最新在线| 狠狠躁夜夜躁人人爽超碰91| 天堂在线精品| 91亚洲免费视频| 欧美成人小视频| 中文字幕欧美日韩一区| 99久久亚洲国产日韩美女| 金瓶狂野欧美性猛交xxxx| 欧美美乳在线| 九色中文视频| 国产专区一区二区三区| 色妞久久福利网| 国产精品久久免费看| 日韩精品一二三区| 欧美xxxx黑人又粗又长| 成人永久免费| 日本精品视频一区二区| 国产美女情趣调教h一区二区| 蜜臀视频一区二区三区| 日韩国产一级片| 欧美做受高潮1| 一区二区三区www| 成人自拍在线| 日日躁夜夜躁aaaabbbb| 91精品婷婷国产综合久久蝌蚪| 欧美一区二区三区思思人| 日本亚洲视频在线| 久久野战av| 在线视频中文字幕| 高清国产在线一区| 亚洲免费资源在线播放| 欧美韩一区二区| 中文在线视频| 日本精品一区二区| 久久精品色欧美aⅴ一区二区| 久久精品亚洲国产奇米99| 亚洲午夜精品一区 二区 三区| 91麻豆一二三四在线| 日韩精品一卡二卡三卡四卡无卡| 国产日本久久| 国产后进白嫩翘臀在线观看视频| 日韩欧美aaa| 九九视频精品免费| 国产精品香蕉一区二区三区| 国产精品一二| 欧美日韩ab| 亚洲精品韩国| 奇米一区二区三区| 国产农村妇女毛片精品久久莱园子 | 欧美亚洲另类激情另类| 欧美日韩精品电影| 亚洲免费在线视频一区 二区| 粉嫩久久99精品久久久久久夜| 日本.亚洲电影| 成全视频全集| 欧美黄色片在线观看| 国产精品久久二区二区| 欧美日本二区| 欧美亚洲福利| 美女一区2区| 日本国产精品| 欧美1区3d| 影音先锋中文字幕一区二区| 欧美黄在线观看| 青青草成人影院| 日本午夜精品久久久| 素人啪啪色综合| 久久99亚洲网美利坚合众国| 欧美成人黄色| 91精品啪在线观看国产手机| 1769在线观看| 欧美视频在线视频精品| 免费精品一区| 亚洲日本久久| 国产成人综合在线观看| 亚洲免费观看高清| 日韩av不卡一区| 成人在线资源网址| 97视频在线观看免费高清完整版在线观看| 91欧美极品| 朝桐光一区二区| 免费看男女www网站入口在线| 国内自拍亚洲| 秋霞av在线| 91大神xh98hx在线播放| 桃花岛tv亚洲品质| 精品国产123区| 国产精品伊人色| 国产精品网站在线播放| 亚洲日本电影在线| 一区二区三区国产视频| 日韩电影在线观看中文字幕| 国产成人精品视频在线| 尤物av无码色av无码| 日韩专区在线| 精品国产精品| 久久久噜噜噜久久中文字幕色伊伊 | 久久久久久久久久码影片| 欧美三级午夜理伦三级富婆| 影音先锋在线视频| 国产精品不卡| 粉嫩av一区二区三区在线播放| 国产日韩欧美精品综合| 午夜a成v人精品| 亚洲欧洲一区二区三区在线观看| 国产精品一区专区欧美日韩| 神马影院一区二区| 国内在线高清免费视频| 欧美aaaaaaaa牛牛影院| 精品一区二区三区免费毛片爱| 久久久久久青草| 成人在线播放| 国产91在线|亚洲| 精品亚洲一区二区三区在线播放| 国产二区视频在线| 欧美亚洲国产一区| 欧美va亚洲va国产综合| 亚洲综合欧美激情| 一本久久综合| 欧美成人免费播放| 九色视频网站在线观看| 国产91精品入口| 亚洲精品国精品久久99热 | 最新国产精品久久精品| 国产999在线| 日本在线视频观看| 久久国产婷婷国产香蕉| 亚洲最新中文字幕| 成年人免费网站| 在线一区欧美| 不卡av在线播放| 激情小说 在线视频| 国产一区三区三区| 国产aaa精品| 色戒汤唯在线| 亚洲国产精品一区二区久久恐怖片| 久久久久久精| 欧美尿孔扩张虐视频| 欧美一级在线视频| 国产精品粉嫩av| 免费观看成人鲁鲁鲁鲁鲁视频| 欧美成人精品h版在线观看| av大片在线看| 不卡视频在线观看| 久久躁日日躁aaaaxxxx| 日本a级片在线观看| 国产精品四虎| 国一区二区在线观看| 午夜久久福利影院| 欧美亚洲日本黄色|