java - 如何使此代码更干燥

标签 java exception-handling dry

所以我有一个生成的类 (PartnerConnection),它向 SalesForce 云平台提供 DML 操作。由于与 SalesForce 或运行代码的系统的连接问题,我们遇到了长期运行的集成过程失败的问题。

为了解决这个问题,我用我命名的AdvancedPartnerConnection 扩展了PartnerConnection 类。 AdvancedPartnerConnection 只是覆盖 PartnerConnection 的方法并用try/catch/retry 逻辑包装它们。 p>

@Override
public QueryResult query(String queryString) throws ConnectionException{
    int attempt = 0;
    ConnectionException lastException = null;
    while(true){
        if(attempt < maxAttempts){ //maxAttempts constant
            if(lastException != null){
                try {
                    //exponentially increase wait times
                    Long sleepTime =(long) Math.pow(sleepBase, attempt) * 300;
                    Thread.sleep(sleepTime);
                } catch (InterruptedException e1) {
                    // something bad has happen, throw the connection exception
                    throw lastException;
                }
            }
            attempt ++;
            try{
                //call super class method
                return super.query(queryString);
            }catch(ConnectionException e){
                lastException = e;
            }
        }else{
            throw lastException;
        }
    }
}

我已经为一些父类(super class)方法实现了这个,唯一的区别是被调用的方法及其参数。如果我决定更改任何重试逻辑,因为我希望它在所有方法中保持一致,这将成为一个真正的痛苦。

有没有人有办法将重试逻辑提取到单独的类或方法中,并可能传入函数调用?我在 .NET 中做过类似的事情,但我不确定如何在 Java 中完成。

最佳答案

您基本上想要捕获对所有对象方法的所有调用,并对所有这些方法应用一些逻辑。 你可以创建一个 Proxy并在 handler 中重试调用方法。

使用这种基于方法签名的方法,您可以决定要做什么。

另一种方法可以使用 AspectJ 或任何其他 AOP 框架,但您的用例添加这种依赖项非常简单,IMO。

如果您想添加一些behaviour 的类不是您的,那么这个解决方案可能不是最优雅的。但是,如果您愿意牺牲一些优雅来获得可维护性(因为您不是在复制代码),那么您可以:

class NotYourClass {
    public void voidMethod() {}
    public int intMethod(int n) { return 0; }
}

要创建一个代理,您必须创建一个包含该类所有方法的接口(interface)。这是糟糕的部分,但这不会对您的应用程序添加任何依赖性。

interface YourInterface {
    public void voidMethod();
    public int intMethod(int n);
}

接下来您需要一个包含行为InvocationHandler

class YourInvocationHandler implements InvocationHandler {
    private final NotYourClass target;

    public YourInvocationHandler(NotYourClass target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
                // Here you must look to the methods that are the ones that you want.
                return method..invoke(target, args);
        } catch (Exception e) {
            // Retry?
            method.invoke(target, args);
        }
    }
}

请记住,这是我的想法。但应该符合这些思路。

如果创建该接口(interface)对您来说是无法接受的,那么您可以查看一些AOP 框架。

关于java - 如何使此代码更干燥,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19737224/

相关文章:

java - 在spring Controller 中上传带有其他参数的文件

python - 根据字符串的值创建变量

javascript - 如何在 Jasmine JS 中重用 beforeEach/afterEach?

c# - add-windowsfeature 无法识别

java - 致命异常 : java. lang.IncompatibleClassChangeError : Couldn't find com. google.a.a.c.a

c# - 如何在.Net中以中间层结构化方式处理错误或异常

c++ - 我违反了 D.R.Y.请帮帮我?

Java 开关按钮

java - Maven 在现有目录中生成原型(prototype)

java - 有没有办法从 EJB 模块访问 HttpSession?