我在代码中使用Java Callable Future。下面是我的主要代码,它使用未来和可调用-
public class TimeoutThread {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(5);
Future<String> future = executor.submit(new Task());
try {
System.out.println("Started..");
System.out.println(future.get(3, TimeUnit.SECONDS));
System.out.println("Finished!");
} catch (TimeoutException e) {
System.out.println("Terminated!");
}
executor.shutdownNow();
}
}
下面是我的Task
类,它实现了可调用接口,我需要根据主机名生成URL,然后使用RestTemplate
调用SERVERS。如果第一个主机名中有任何异常,那么我将为另一个主机名生成URL,并尝试进行调用。
class Task implements Callable<String> {
private static RestTemplate restTemplate = new RestTemplate();
@Override
public String call() throws Exception {
//.. some code
for(String hostname : hostnames) {
if(hostname == null) {
continue;
}
try {
String url = generateURL(hostname);
response = restTemplate.getForObject(url, String.class);
// make a response and then break
break;
} catch (Exception ex) {
ex.printStackTrace(); // use logger
}
}
}
}
那么我的问题是,我应该将RestTemplate
声明为静态全局变量吗?或者在这种情况下它不应该是静态的?
static
或实例都无关紧要。
RestTemplate
发出HTTP请求的方法是线程安全的,所以每个Task
实例有一个RestTemplate
实例,还是所有Task
实例都有一个共享实例都无关紧要(垃圾收集除外)。
就我个人而言,我会在Task
类之外创建RestTemplate
,并将其作为参数传递给Task
构造函数。(尽可能使用控制反转。)
从并发的角度来看,这并不重要。RestTemplate
是线程安全的,因此单个实例或多个实例与程序的正常运行无关。
但是您可能需要考虑AsyncRestTemplate
,如图所示。
此外,正如其他人所提到的,您应该考虑一种IoC方法来将REST客户端的创建与其使用分开。马丁·福勒的这篇文章是关于这个话题的开创性讨论。
在我的特殊情况下,我发现了一些原因,说明为什么人们可能想要拥有多个RestTemplate
实例。
RestTemplate是一种调用远程端点的方法,但HTTP集成看起来非常简单,当你开始发现不适用于所有API调用的特殊场景时,你就会意识到你需要一种方法来逐个定义一些设置。
此类场景的示例如下:
- 我们公司有不同的团队,我们错误地没有就我们想要在模型中使用的时间格式达成一致。现在,来自不同团队的不同API使用不同的时间格式,这迫使我们为这些情况定义不同的JSON映射器设置。如果必须调用第三方服务,也可能发生这种情况
- 并不是所有我们调用的API都具有相同的服务级别协议,或者全年的行为都相同。在旺季,一些API可能需要支持更多流量等。这意味着不同API的连接超时设置可能不同,有时甚至取决于需求。因此,连接超时、读取超时和写入超时等设置可能会根据调用的服务进行不同的配置
- 也许断路器设置,就像Hytrix的设置一样,可能需要按服务进行配置,因此每个服务都有一个RestTemplate实例,可以根据具体情况配置设置
如前所述,RestTemplate是线程安全的。
但是,对于单元测试,使用静态变量会给模拟他的调用带来一些问题。因此,考虑使用类构造函数注入RestTemplate:
@Service
class LoginService {
private final RestTemplate restTemplate;
public LoginService(final RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
}