Java:如何在没有复制粘贴代码的情况下处理重试?

Art*_*tem 8 java copy-paste exception

当我不得不为数据库和网络操作进行重试时,我有多种情况.无论我到哪里,我都有以下类型的代码:

    for (int iteration = 1; ; iteration++) {
        try {
            data = doSomethingUseful(data);

            break;
        } catch (SomeException | AndAnotherException e) {
            if (iteration == helper.getNumberOfRetries()) {
                throw e;
            } else {
                errorReporter.reportError("Got following error for data = {}. Continue trying after delay...", data, e);
                utilities.defaultDelayForIteration(iteration);
                handleSpecificCase(data);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

问题是这个代码模式在我的类中被复制粘贴.这真的很糟糕.我无法弄清楚如何摆脱这种for-break-catch复制粘贴模式,因为我通常会得到不同的异常来处理,我想记录我失败的数据(通常也是不同的方式).

有没有一种方法可以避免Java 7中的这种复制粘贴?

编辑:我确实使用guice进行依赖注入.我确实检查了异常.可能有多个变量而不是一个数据,它们都是不同的类型.

编辑2:AOP方法对我来说是最有希望的.

mer*_*ike 5

副手,我可以想到两种不同的方法:

如果可以以声明方式表示异常处理中的差异,则可以使用AOP编写围绕方法的异常处理代码.然后,您的业务代码可能如下所示:

@Retry(times = 3, loglevel = LogLevel.INFO)
List<User> getActiveUsers() throws DatabaseException {
    // talk to the database
}
Run Code Online (Sandbox Code Playgroud)

优点是很容易向方法添加重试行为,缺点是编织建议的复杂性(你只需要实现一次.如果你使用依赖注入库,很可能会提供方法拦截)支持).

另一种方法是使用命令模式:

abstract class Retrieable<I,O> {
    private final LogLevel logLevel;

    protected Retrieable(LogLevel loglevel) {
        this.logLevel = loglevel;
    }

    protected abstract O call(I input);

    // subclasses may override to perform custom logic.
    protected void handle(RuntimeException e) {
        // log the exception. 
    }

    public O execute(I input) {
        for (int iteration = 1; ; iteration++) {
            try {
                return call(input);
            } catch (RuntimeException e) {
                if (iteration == helper.getNumberOfRetries()) {
                    throw e;
                } else {
                    handle();
                    utilities.defaultDelayForIteration(iteration);
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

命令模式的问题是方法参数.您被限制为单个参数,并且对于调用者而言,泛型相当不实用.此外,它不适用于已检查的异常.从好的方面来说,没有花哨的AOP东西:-)


yeg*_*256 5

如前所述,AOP 和 Java 注释是一个不错的选择。我会建议使用jcabi-aspects 中的一种只读机制:

@RetryOnFailure(attempts = 2, delay = 10, verbose = false)
public String load(URL url) {
  return url.openConnection().getContent();
}
Run Code Online (Sandbox Code Playgroud)

另请阅读此博客文章:http : //www.yegor256.com/2014/08/15/retry-java-method-on-exception.html