RestTemplate应该是全局声明的静态吗?

时间:2014-01-15 18:35:03

标签: java multithreading resttemplate callable

我在我的代码中使用Java Callable Future。下面是我使用未来和callables的主要代码 -

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类,它实现了Callable接口,我需要根据我们拥有的主机名生成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声明为静态全局变量吗?或者在这种情况下它不应该是静态的?

4 个答案:

答案 0 :(得分:13)

两种方式都无关紧要,static或实例。

RestTemplate用于发出HTTP请求的方法是线程安全的,因此每个RestTemplate实例都有Task个实例,或者所有Task个实例的共享实例都无关紧要(垃圾收集除外)。

就个人而言,我会在RestTemplate类之外创建Task并将其作为参数传递给Task构造函数。 (尽可能使用控制反转。)

答案 1 :(得分:3)

从并发的角度来看,这无关紧要。 RestTemplate是线程安全的,因此单个实​​例或多个实例与程序的正常运行无关。

但您可能需要考虑AsyncRestTemplate,而不是here

另外,正如其他人所提到的,您应该考虑使用IoC方法将REST客户端的创建与其使用分开。 Martin Fowler撰写的This文章是关于该主题的开创性讨论。

答案 2 :(得分:2)

在我的特定情况下,我找到了一些原因,为什么人们可能希望拥有多个RestTemplate的实例。

RestTemplate是一种调用远程端点的方法,但是HTTP集成看起来很简单,当你开始发现不适用于所有API调用的特殊场景时,你会发现需要一种方法来定义一些设置。个案基础。

此类方案的示例如下:

  • 我们公司有不同的团队,但我们错误地认为我们想要在我们的模型中使用的时间格式。现在,来自不同团队的不同API使用不同的时间格式,这迫使我们为这些案例定义不同的JSON映射器设置。如果您必须调用第三方服务,也可能发生这种情况。
  • 并非所有我们调用的API都具有相同的服务级别协议,或者全年都表现相同。在旺季,一些API可能必须支持更多流量等。这意味着不同API的连接超时设置可能不同,有时甚至取决于要求。因此,根据您要调用的服务,可能会对连接超时,读取超时和写入超时等设置进行不同的配置。
  • 也许可能需要为每个服务配置断路器设置(如Hytrix的设置),因此每个服务具有RestTemplate实例可以更多地根据具体情况配置设置。

答案 3 :(得分:1)

如前所述,RestTemplate是线程安全的。

但是,对于单元测试,使用静态变量将给您带来一些模拟他的调用的问题。因此,考虑使用类构造函数注入RestTemplate:

@Service
class LoginService {

    private final RestTemplate restTemplate;

    public LoginService(final RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }
}