该工具只是对Guava中Retryer拙劣的模仿。意在学习其Java8使用方式,代码解耦精髓。
package com.fast.cattsoft.util;
import java.util.concurrent.ExecutionException;
public interface RetryResult<V> {
boolean hasResult();
boolean hasException();
V getResult() throws IllegalAccessException;
V get() throws ExecutionException;
Throwable getException();
int getRetryCount();
}
package com.fast.cattsoft.util;
public class SuccessRetryResult<R> implements RetryResult<R> {
private R result;
private int tryCount;
private long intervaTime;
public SuccessRetryResult(R result, int tryCount, long intervaTime) {
this.result = result;
this.tryCount = tryCount;
this.intervaTime = intervaTime;
}
@Override
public boolean hasResult() {
return true;
}
@Override
public boolean hasException() {
return false;
}
@Override
public R getResult() {
return result;
}
@Override
public R get() {
return result;
}
@Override
public Throwable getException() {
return null;
}
@Override
public int getRetryCount() {
return 0;
}
}
package com.fast.cattsoft.util;
import java.util.concurrent.ExecutionException;
public class ExceptionRetryResult<R> implements RetryResult<R> {
private ExecutionException e;
private int tryCount;
private long intervaTime;
ExceptionRetryResult(ExecutionException e, int tryCount, long intervaTime) {
this.e = e;
this.tryCount = tryCount;
this.intervaTime = intervaTime;
}
@Override
public boolean hasResult() {
return false;
}
@Override
public boolean hasException() {
return true;
}
@Override
public R getResult() throws IllegalAccessException {
throw new IllegalAccessException("");
}
@Override
public R get() throws ExecutionException {
throw e;
}
@Override
public Throwable getException() {
return e.getCause();
}
@Override
public int getRetryCount() {
return tryCount;
}
}
package com.fast.cattsoft.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
public class RetryBuild<V> {
private List<Predicate<RetryResult<V>>> predicates =
new ArrayList<Predicate<RetryResult<V>>>(Collections.singleton(new Predicate<RetryResult<V>>() {
@Override
public boolean test(RetryResult<V> vRetryResult) {
return false;
}
}));
//重试次数
private int tryCount = 1;
//每次重试失败后间隔时间
private long intervaTime = 1;
public static <V> RetryBuild<V> newBuild() {
return new RetryBuild<V>();
}
public RetryBuild<V> buildTryCount(int tryCount) {
this.tryCount = tryCount;
return this;
}
public RetryBuild<V> buildIntervaTime(long intervaTime) {
this.intervaTime = intervaTime;
return this;
}
public RetryBuild<V> buildThrows(Class<? extends Throwable> throwables) {
predicates.add(new ExceptionClassPredicate<V>(throwables));
return this;
}
public RetryBuild<V> buildResult(Predicate<V> predicate) {
predicates.add(new SuccessPredicate<V>(predicate));
return this;
}
public Retry<V> build() {
return new Retry<V>(tryCount, intervaTime, new OnPredicate<V>(predicates));
}
}
class ExceptionClassPredicate<V> implements Predicate<RetryResult<V>> {
private Class<? extends Throwable> exception;
public ExceptionClassPredicate(Class<? extends Throwable> exception) {
this.exception = exception;
}
@Override
public boolean test(RetryResult<V> vRetryResult) {
if (!vRetryResult.hasException()) {
return false;
}
return exception.isAssignableFrom(vRetryResult.getException().getClass());
}
}
class SuccessPredicate<V> implements Predicate<RetryResult<V>> {
private Predicate<V> delegate;
public SuccessPredicate(Predicate<V> predicate) {
this.delegate = predicate;
}
@Override
public boolean test(RetryResult<V> vRetryResult) {
if (!vRetryResult.hasResult()) {
return false;
}
try {
V result = vRetryResult.getResult();
boolean test = delegate.test(result);
return test;
} catch (Exception e) {
throw new RuntimeException("");
}
}
}
class ExceptionPredicate<V> implements Predicate<RetryResult<V>> {
private Predicate<Throwable> delegate;
public ExceptionPredicate(Predicate<Throwable> delegate) {
this.delegate = delegate;
}
@Override
public boolean test(RetryResult<V> vRetryResult) {
if (!vRetryResult.hasException()) {
return false;
}
return delegate.test(vRetryResult.getException());
}
}
class OnPredicate<V> implements Predicate<RetryResult<V>> {
//private List<? extends Predicate<? super V>> predicates;
private List<Predicate<RetryResult<V>>> predicates;
public OnPredicate(List<Predicate<RetryResult<V>>> predicates) {
this.predicates = predicates;
}
@Override
public boolean test(RetryResult<V> vRetryResult) {
for (int i = 0; i < predicates.size(); i++) {
if (predicates.get(i).test(vRetryResult)) {
return true;
}
}
return false;
}
}
package com.fast.cattsoft.util;
import com.github.rholder.retry.*;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestClientException;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* 重试工具类
*
* @param <V>
*/
public class Retry<V> {
//重试次数
private int tryCount = 1;
//每次重试失败后间隔时间
private long intervaTime = 1;
private Predicate<RetryResult<V>> predicate;
public Retry(int tryCount, long intervaTime, Predicate<RetryResult<V>> predicate) {
this.tryCount = tryCount;
this.intervaTime = intervaTime;
this.predicate = predicate;
}
public V call(Supplier<V> supplier) throws ExecutionException {
int currTryCount = 0;
for (int i = 0; ; i++) {
RetryResult<V> retryResult;
try {
V result = supplier.get();
retryResult = new SuccessRetryResult(result, tryCount, intervaTime);
} catch (Exception e) {
retryResult =
new ExceptionRetryResult(new ExecutionException(e), tryCount, intervaTime);
} finally {
currTryCount++;
}
if (!predicate.test(retryResult)) {
return retryResult.get();
}
if (currTryCount >= this.tryCount) {
throw new RuntimeException("retry number more than " + this.tryCount);
} else {
try {
Thread.sleep(this.intervaTime);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("");
}
}
}
}
public static void main(String[] args) throws Throwable {
customReTry();
//guavaRetry();
}
public static void customReTry() throws Throwable {
Retry<Integer> build = RetryBuild.<Integer>newBuild()
.buildTryCount(3)
.buildIntervaTime(2000l)
.buildResult(res -> {
System.out.println("result has to than " + 6);
return res > 6;
})
.buildThrows(ArithmeticException.class)
.build();
Integer call = build.call(() -> {
int i = 0;
//int b = 4 / i;
return 5;
});
System.out.println("result :" + call);
}
//可以参考guava重试代码
public static void guavaRetry() throws ExecutionException, RetryException {
new ArrayList<>(1);
Retryer<Integer> build = RetryerBuilder.<Integer>newBuilder()
// .retryIfException(e -> e.getMessage().contains(""))
.retryIfResult(e -> {
System.out.println("result has to than 5");
return e > 5;
})
.retryIfExceptionOfType(ArithmeticException.class)
.withStopStrategy(StopStrategies.stopAfterAttempt(1))
.withWaitStrategy(WaitStrategies.fixedWait(3, TimeUnit.SECONDS))
.build();
Integer call = build.call(() -> {
int i = 0;
//int b = 4 / i;
return 5;
});
System.out.println("result :" + call);
}
}