我向Web服务发送了多个请求,下面有一个请求示例。对于我的应用程序来说,从Web服务获得答案非常重要,因此如果有异常应用程序将尝试多次以获得答案。
因为这样可以获得简单的东西
deviceList = serviceAdapter.getDevices();
变为下面的代码。
boolean flag = true;
int counter = 1;
List<Device> deviceList = null;
while (flag) {
try {
deviceList = serviceAdapter.getDevices();
flag = false;
} catch (Exception e) {
try {
if (counter == 5) {
System.out.println("Timeout Occured!");
flag = false;
} else {
Thread.sleep(1000 * counter);
counter++;
}
} catch (InterruptedException e1) {
}
}
}
在我的应用程序中,我有很多请求,这意味着会有更多丑陋的代码。有没有办法我将我的请求方法作为参数调用另一种方法,如下所示:
deviceList = wrapperMethod(serviceAdapter.getDevices());
问题是会有不同类型的请求,因此它们将返回不同类型的对象(列表,数组,字符串,整数),并且它们的参数将会改变。这个问题在java中是否有合适的解决方案?
答案 0 :(得分:0)
您可以将Supplier<T>
传递给wrapperMethod
:
public static <T> T wrapperMethod (Supplier<T> supp) {
boolean flag = true;
int counter = 1;
T value = null;
while (flag) {
try {
value = supp.get();
flag = false;
} catch (Exception e) {
try {
if (counter == 5) {
System.out.println("Timeout Occured!");
flag = false;
} else {
Thread.sleep(1000 * counter);
counter++;
}
} catch (InterruptedException e1) {
}
}
}
}
并将其命名为:
List<Device> deviceList = wrapperMethod (() -> serviceAdapter.getDevices());
但是,我担心它会限制你在lambda表达式中调用的方法只能抛出RuntimeException
s。
答案 1 :(得分:0)
您可以使用jcabi-aspects
中的@RetryOnFailure
注释
创建一个包装器方法,然后对其进行注释以在异常时启用自动重试
举个例子:
@RetryOnFailure(attempts = 5)
List<Device> retryWhenFailed(ServiceAdapter serviceAdapter) throws Exception {
return serviceAdapter.getDevices();
}
答案 2 :(得分:0)
您可以使用某些命令实现来执行某些特定代码:
这是一个简单的命令示例
class SayHello implements Command{
@Override
public void run() {System.out.println("Hello World");}
}
class KillMe implements Command{
public void run() { throw new RuntimeException();};
}
还有几个实现:
Command
执行这些方法所需要做的就是接收public static void execCommand(Command cmd) {
cmd.run();
}
的实例并运行方法:
public static void main(String[] args) {
execCommand(new SayHello());
execCommand(new KillMe());
}
并使用此
execCommand(() -> System.out.println("Say goodbye"));
Hello World
线程&#34; main&#34;中的例外情况了java.lang.RuntimeException
它也接受lambda表达式:
public class Test{
public static void testMe() {
System.out.println("I work");
}
}
execCommand(Test::testMe);
方法参考:
Exception
请注意,我没有指定这可能会抛出RuntimeException
因此我仅限于void run() throws Exception
之类的未经检查的异常,但当然public class Test {
public static void main(String[] args) {
try {
execCommand(new SayHello());
execCommand(() -> System.out.println("Say goodbye"));
execCommand(Test::testMe);
execCommand(new KillMe());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void testMe() throws IOException{
System.out.println("I work");
}
public static void execCommand(Command cmd) throws Exception {
cmd.run();
}
}
interface Command{
void run() throws Exception;
}
class SayHello implements Command{
@Override
public void run() {System.out.println("Hello World");}
}
class KillMe implements Command{
public void run() { throw new RuntimeException();};
}
可能是一个解决方案。这样你就可以做任何你想做的事。
完整示例(有例外):
Hello World
Say goodbye
I work
Exception in thread "main" java.lang.RuntimeException
at main.KillMe.run(Test.java:39)
at main.Test.execCommand(Test.java:25)
at main.Test.main(Test.java:17)
输出:
my_class
答案 3 :(得分:0)
此解决方案使用Generics能够处理具有大多数相同代码的不同Object和Runnable来执行提取。
使用此解决方案,你只需要编写从ServiceAdapter<T extends Fetchable>
,以实现撷取针对每个不同的类中的数据的逻辑延伸的不同的适配器(这将具有实施Fetchable
)。
定义一个接口,用于删除不同服务可以获取的对象。
package so50488682;
public interface Fetchable {
}
要检索的ojbect实现此接口,因此您可以对不同的类使用相同的代码。
package so50488682;
public class Device implements Fetchable{
private String id;
public Device(String id) {
this.id = id;
}
public String toString() {
return "I am device " + id;
}
}
定义一个抽象ServiceAdapter
,不同的服务适配器将扩展该抽象throws Exception
以实现要检索的每种对象的逻辑。我们将FetcherService
添加到get()方法中,因此此方法只是将异常处理委托给package so50488682;
import java.util.List;
public abstract class ServiceAdapter<T extends Fetchable> {
public abstract List<T> get() throws Exception;
}
并确定它是否应该重试或失败。
package so50488682;
import java.util.ArrayList;
import java.util.List;
public class DeviceServiceAdapter extends ServiceAdapter<Device>{
@Override
public List<Device> get() throws Exception{
List<Device> rtn = new ArrayList<>();
// fetch the data and put it into rtn, this is a mock
Device d = new Device("1");
rtn.add(d);
d = new Device("2");
rtn.add(d);
d = new Device("3");
rtn.add(d);
//
return rtn;
}
}
这是获取类Device对象的实现示例。
public class FetcherService<T extends Fetchable> implements Runnable{
List<T> result = new ArrayList<>();
ServiceAdapter<T> serviceAdapter;
@Override
public void run() {
boolean flag = true;
int counter = 1;
while (flag) {
try {
result = serviceAdapter.get();
flag = false;
} catch (Exception e) {
try {
if (counter == 5) {
System.out.println("Timeout Occured!");
flag = false;
} else {
Thread.sleep(1000 * counter);
counter++;
}
} catch (InterruptedException e1) {
throw new RuntimeException("Got Interrupted in sleep", e);
}
}
}
}
public List<T> getResult() {
return result;
}
public void setResult(List<T> result) {
this.result = result;
}
public void setAdapter(ServiceAdapter<T> adapter) {
this.serviceAdapter = adapter;
}
}
最后,这是运行不同服务适配器的通用解决方案。
package so50488682;
import java.util.List;
public class SO50488682 {
public static void main(String args[]) {
try {
DeviceServiceAdapter deviceServiceAdapter = new DeviceServiceAdapter();
FetcherService<Device> deviceFetcherService = new FetcherService<>();
deviceFetcherService.setAdapter(deviceServiceAdapter);
deviceFetcherService.run();
List<Device> devices = deviceFetcherService.getResult();
for(Device device : devices) {
System.out.println(device.toString());
}
}catch(Exception e) {
System.out.println("Exception after retrying a couple of times");
e.printStackTrace();
}
}
}
从主程序或调用程序中它的工作原理如下:
{{1}}