欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于Spring-AOP實(shí)現(xiàn)自定義分片工具詳解

 更新時(shí)間:2022年11月22日 14:05:53   作者:陳昌浩  
隨著數(shù)據(jù)量的增長,在與其他系統(tǒng)交互時(shí),批量接口會出現(xiàn)超時(shí)現(xiàn)象,發(fā)現(xiàn)原批量接口在實(shí)現(xiàn)時(shí),沒有做分片處理。由于與其他系統(tǒng)交互比較多,一個(gè)一個(gè)接口去做分片優(yōu)化,改動量較大,所以考慮通過AOP解決此問題,感興趣的可以了解一下

1.背景

隨著數(shù)據(jù)量的增長,發(fā)現(xiàn)系統(tǒng)在與其他系統(tǒng)交互時(shí),批量接口會出現(xiàn)超時(shí)現(xiàn)象,發(fā)現(xiàn)原批量接口在實(shí)現(xiàn)時(shí),沒有做分片處理,當(dāng)數(shù)據(jù)過大時(shí)或超過其他系統(tǒng)閾值時(shí),就會出現(xiàn)錯(cuò)誤。由于與其他系統(tǒng)交互比較多,一個(gè)一個(gè)接口去做分片優(yōu)化,改動量較大,所以考慮通過AOP解決此問題。

2.Spring-AOP

AOP (Aspect Orient Programming),直譯過來就是 面向切面編程。AOP 是一種編程思想,是面向?qū)ο缶幊蹋∣OP)的一種補(bǔ)充。面向?qū)ο缶幊虒⒊绦虺橄蟪筛鱾€(gè)層次的對象,而面向切面編程是將程序抽象成各個(gè)切面。

Spring 中的 AOP 是通過動態(tài)代理實(shí)現(xiàn)的。 Spring AOP 不能攔截對對象字段的修改,也不支持構(gòu)造器連接點(diǎn),我們無法在 Bean 創(chuàng)建時(shí)應(yīng)用通知。

3.功能實(shí)現(xiàn)

自定義分片處理分三個(gè)部分:自定義注解(MethodPartAndRetryer)、重試器(RetryUtil)、切面實(shí)現(xiàn)(RetryAspectAop)。

3.1 MethodPartAndRetryer

源碼

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MethodPartAndRetryer {
    /**
     * 失敗重試次數(shù) 
     * @return
     */
    int times() default 3;
    /**
     * 失敗間隔執(zhí)行時(shí)間 300毫秒
     * @return
     */
    long waitTime() default 300L;
    /**
     * 分片大小     
     * @return
     */
    int parts() default 200;
}

@interface說明這個(gè)類是個(gè)注解。

@Target是這個(gè)注解的作用域

public enum ElementType {
    /** 類、接口(包括注釋類型)或枚舉聲明   */
    TYPE,
    /** 字段聲明(包括枚舉常量) */
    FIELD,
    /** 方法聲明 */
    METHOD,
    /** 正式的參數(shù)聲明 */
    PARAMETER,
    /** 構(gòu)造函數(shù)聲明 */
    CONSTRUCTOR,
    /** 局部變量聲明 */
    LOCAL_VARIABLE,
    /** 注釋類型聲明*/
    ANNOTATION_TYPE,
    /** 程序包聲明 */
    PACKAGE,
    /**類型參數(shù)聲明*/
    TYPE_PARAMETER,
    /**類型的使用*/
    TYPE_USE
}

@Retention注解的生命周期

public enum RetentionPolicy {
    /** 編譯器處理完后不存儲在class中*/
    SOURCE,
    /**注釋將被編譯器記錄在類文件中,但不需要在運(yùn)行時(shí)被VM保留。 這是默認(rèn)值*/
    CLASS,
    /**編譯器存儲在class中,可以由虛擬機(jī)讀取*/
    RUNTIME
}

times():接口調(diào)用失敗時(shí),重試的次數(shù)。

waitTime():接口調(diào)用失敗是,間隔多長時(shí)間再次調(diào)用。

int parts():進(jìn)行分片時(shí),每個(gè)分片的大小。

3.2 RetryUtil

源碼

public class RetryUtil<V> {

???????    public Retryer<V> getDefaultRetryer(int times,long waitTime) {
        Retryer<V> retryer = RetryerBuilder.<V>newBuilder()
                .retryIfException()
                .retryIfRuntimeException()
                .retryIfExceptionOfType(Exception.class)
                .withWaitStrategy(WaitStrategies.fixedWait(waitTime, TimeUnit.MILLISECONDS))
                .withStopStrategy(StopStrategies.stopAfterAttempt(times))
                .build();
        return retryer;
    }
}

說明

  • RetryerBuilder:是用于配置和創(chuàng)建Retryer的構(gòu)建器。
  • retryIfException:拋出runtime異常、checked異常時(shí)都會重試,但是拋出error不會重試。
  • retryIfRuntimeException:只會在拋runtime異常的時(shí)候才重試,checked異常和error都不重試。
  • retryIfExceptionOfType:允許我們只在發(fā)生特定異常的時(shí)候才重試。
  • withWaitStrategy:等待策略,每次請求間隔。
  • withStopStrategy:停止策略,重試多少次后停止。

3.3 RetryAspectAop

源碼:

public class RetryAspectAop {
      public Object around(final ProceedingJoinPoint point) throws Throwable {
        Object result = null;
        final Object[] args = point.getArgs();
        boolean isHandler1 = isHandler(args);
        if (isHandler1) {
            String className = point.getSignature().getDeclaringTypeName();
            String methodName = point.getSignature().getName();
            Object firstArg = args[0];
            List<Object> paramList = (List<Object>) firstArg;
            //獲取方法信息
            Method method = getCurrentMethod(point);
            //獲取注解信息
            MethodPartAndRetryer retryable = AnnotationUtils.getAnnotation(method, MethodPartAndRetryer.class);
            //重試機(jī)制
            Retryer<Object> retryer = new RetryUtil<Object>().getDefaultRetryer(retryable.times(),retryable.waitTime());
            //分片
            List<List<Object>> requestList = Lists.partition(paramList, retryable.parts());
            for (List<Object> partList : requestList) {
                args[0] = partList;
                Object tempResult = retryer.call(new Callable<Object>() {
                    @Override
                    public Object call() throws Exception {
                        try {
                            return point.proceed(args);
                        } catch (Throwable throwable) {
                            log.error(String.format("分片重試報(bào)錯(cuò),類%s-方法%s",className,methodName),throwable);
                            throw new RuntimeException("分片重試出錯(cuò)");
                        }
                    }
                });
                if (null != tempResult) {
                    if (tempResult instanceof Boolean) {
                        if (!((Boolean) tempResult)) {
                            log.error(String.format("分片執(zhí)行報(bào)錯(cuò)返回類型不能轉(zhuǎn)化bolean,類%s-方法%s",className,methodName));
                            throw new RuntimeException("分片執(zhí)行報(bào)錯(cuò)!");
                        }
                        result = tempResult;
                    } else if (tempResult instanceof List) {
                        if(result ==null){
                            result =Lists.newArrayList();
                        }
                        ((List) result).addAll((List) tempResult);
                    }else {
                        log.error(String.format("分片執(zhí)行返回的類型不支持,類%s-方法%s",className,methodName));
                        throw new RuntimeException("不支持該返回類型");
                    }
                } else {
                    log.error(String.format("分片執(zhí)行返回的結(jié)果為空,類%s-方法%s",className,methodName));
                    throw new RuntimeException("調(diào)用結(jié)果為空");
                }
            }
        } else {
            result = point.proceed(args);
        }
        return result;
    }
    private boolean isHandler(Object[] args) {
        boolean isHandler = false;
        if (null != args && args.length > 0) {
            Object firstArg = args[0];
            //如果第一個(gè)參數(shù)是list 并且數(shù)量大于1
            if (firstArg!=null&&firstArg instanceof List &&((List) firstArg).size()>1) {
                isHandler = true;
            }
        }
        return isHandler;
    }
    private Method getCurrentMethod(ProceedingJoinPoint point) {
        try {
            Signature sig = point.getSignature();
            MethodSignature msig = (MethodSignature) sig;
            Object target = point.getTarget();
            return target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }
}

說明:

getCurrentMethod:獲取方法信息即要做分片的批量調(diào)用的接口。

isHandler1:判斷是否要做分片處理,只有第一參數(shù)是list并且list 的值大于1時(shí)才做分片處理。

around:具體分片邏輯。

  • 獲取要分片方法的參數(shù)。
  • 判斷是否要做分片處理。
  • 獲取方法。
  • 獲取重試次數(shù)、重試間隔時(shí)間和分片大小。
  • 生成重試器。
  • 根據(jù)設(shè)置的分片大小,做分片處理。

調(diào)用批量接口并處理結(jié)果。

4.功能使用

4.1 配置文件

4.2 代碼示例

@MethodPartAndRetryer(parts=100)
public Boolean writeBackOfGoodsSN(List<SerialDTO> listSerial,ObCheckWorker workerData)

只要在需要做分片的批量接口方法上,加上MethodPartAndRetryer注解就可以,重試次數(shù)、重試間隔時(shí)間和分片大小可以在注解時(shí)設(shè)置,也可以使用默認(rèn)值。

5.小結(jié)

通過自定義分片工具,可以快速地對老代碼進(jìn)行分片處理,而且增加了重試機(jī)制,提高了程序的可用性,提高了對老代碼的重構(gòu)效率。

到此這篇關(guān)于基于SpringAOP實(shí)現(xiàn)自定義分片工具詳解的文章就介紹到這了,更多相關(guān)SpringAOP自定義分片工具內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 在idea里如何調(diào)整maven內(nèi)存

    在idea里如何調(diào)整maven內(nèi)存

    這篇文章主要介紹了在idea里如何調(diào)整maven內(nèi)存問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-09-09
  • 淺談一下單體架構(gòu)的缺點(diǎn)是什么

    淺談一下單體架構(gòu)的缺點(diǎn)是什么

    這篇文章主要介紹了單體架構(gòu)的缺點(diǎn)是什么,通常我們所使用的傳統(tǒng)單體應(yīng)用架構(gòu)都是模塊化的設(shè)計(jì)邏輯,程序在編寫完成后會被打包并部署為一個(gè)具體的應(yīng)用,而應(yīng)用的格式則依賴于相應(yīng)的應(yīng)用語言和框架,需要的朋友可以參考下
    2023-04-04
  • SpringBoot如何配置tomcat access日志

    SpringBoot如何配置tomcat access日志

    access日志記錄了每一個(gè)HTTP請求的信息,包括請求的來源、請求的資源、響應(yīng)狀態(tài)碼等,常常用來做數(shù)據(jù)統(tǒng)計(jì)、性能監(jiān)控,比如通過分析訪問日志,可以發(fā)現(xiàn)性能瓶頸和優(yōu)化機(jī)會,提升應(yīng)用的響應(yīng)速度等,這篇文章主要介紹了SpringBoot配置tomcat access日志,需要的朋友可以參考下
    2024-05-05
  • java HttpClient傳輸json格式的參數(shù)實(shí)例講解

    java HttpClient傳輸json格式的參數(shù)實(shí)例講解

    這篇文章主要介紹了java HttpClient傳輸json格式的參數(shù)實(shí)例講解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • java編譯時(shí)出現(xiàn)使用了未經(jīng)檢查或不安全的操作解決方法

    java編譯時(shí)出現(xiàn)使用了未經(jīng)檢查或不安全的操作解決方法

    這篇文章主要介紹了java編譯時(shí)出現(xiàn)使用了未經(jīng)檢查或不安全的操作的解決方法,需要的朋友可以參考下
    2014-03-03
  • Java不帶break將導(dǎo)致case穿透問題

    Java不帶break將導(dǎo)致case穿透問題

    這篇文章主要介紹了Java不帶break將導(dǎo)致case穿透問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • Spring框架web項(xiàng)目實(shí)戰(zhàn)全代碼分享

    Spring框架web項(xiàng)目實(shí)戰(zhàn)全代碼分享

    這篇文章主要介紹了Spring框架web項(xiàng)目實(shí)戰(zhàn)全代碼分享,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • mybatis通過TypeHandler?list轉(zhuǎn)換string類型轉(zhuǎn)換方式

    mybatis通過TypeHandler?list轉(zhuǎn)換string類型轉(zhuǎn)換方式

    這篇文章主要介紹了mybatis通過TypeHandler?list轉(zhuǎn)換string類型轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Java中ArrayIndexOutOfBoundsException 異常報(bào)錯(cuò)的解決方案

    Java中ArrayIndexOutOfBoundsException 異常報(bào)錯(cuò)的解決方案

    本文主要介紹了Java中ArrayIndexOutOfBoundsException 異常報(bào)錯(cuò)的解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • spring-boot實(shí)現(xiàn)增加自定義filter(新)

    spring-boot實(shí)現(xiàn)增加自定義filter(新)

    本篇文章主要介紹了spring-boot實(shí)現(xiàn)增加自定義filter(新),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-05-05

最新評論