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

Posted

技术标签:

【中文标题】RestTemplate 应该是静态全局声明的吗?【英文标题】:RestTemplate should be static globally declared? 【发布时间】:2014-02-04 09:39:14 【问题描述】:

我在我的代码中使用 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 类,它实现了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 声明为静态全局变量吗?或者在这种情况下它不应该是静态的?

【问题讨论】:

【参考方案1】:

static 或实例都无所谓。

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

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

【讨论】:

“就我个人而言,我会创建...”或使用依赖注入 ;) +1 @Rc 对,这就是我的意思,尽可能反转控制。如果可能,也可以使用 DI 容器。 @SotiriosDelimanolis:感谢您的建议。您能否提供一个示例,如何在类外部创建 RestTemplate,然后将其作为参数传递给 Task 构造函数? @Akiweb 创建一个接受RestTemplate 参数的Task 构造函数。然后执行new Task(restTemplate),其中restTemplate 是调用者管理的RestTemplate 引用。 谢谢。但是这样做有什么好处呢?只是想了解我的做法和您建议的方式有什么不同?【参考方案2】:

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

但您可能需要考虑AsyncRestTemplate,而不是如图所示here。

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

【讨论】:

@Vidya 我也有类似的问题here 与RestTemplate 相关,你上次帮助了我。如果可能的话,你能帮我吗?非常感谢任何帮助。 我没有看到同步在 RestTemplate 或实现请求执行逻辑的类中的任何地方使用。它是如何线程安全的?【参考方案3】:

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

RestTemplate 是一种调用远程端点的方法,但是 HTTP 集成看起来非常简单,当您开始发现不适用于所有 API 调用的特殊场景时,您就会意识到您需要一种方法来定义一些设置视情况而定。

此类场景的示例如下:

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

【讨论】:

拥有多个 RestTemplate 的另一个用例是我有一个应用程序与多个 HTTP 服务器交互,每个 HTTP 服务器具有不同的凭据和身份验证类型。对于每台服务器,我都有不同的 RestTemplate。 关于第 2 点,即使在初始化 RestTemplate 之后,您也不能更改 requestFactory 的超时时间吗?因此 ServiceA.methodA() 可以在发出请求之前动态设置读取超时,ServiceB.methodA() 也是如此。如果我错了,请纠正我,因为我正试图在我的项目中实现一个好的设计。谢谢 同意,我们也有类似的情况。在我们的应用程序中,我们需要连接到 3 个或更多不同的 HTTP/HTTPS 服务器,并且我们必须为每个服务器定义超时和自定义的 HTTPClient。因此,对于某些人来说,我们必须使用来自HttpComponentsClientHttpRequestFactory 的 restTemplate,它具有使用自己的可配置客户端和少数 SimpleClientHttpRequestFactory 的功能。因此我们最终拥有单独的 RestTemplate (尽管可以使用相同类型的 minimuim)。不过,如果有人有任何除此之外的好方法,请分享。【参考方案4】:

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

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

@Service
class LoginService 

    private final RestTemplate restTemplate;

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

【讨论】:

以上是关于RestTemplate 应该是静态全局声明的吗?的主要内容,如果未能解决你的问题,请参考以下文章

单例实例声明为 GetInstance 方法的静态变量,它是线程安全的吗? [复制]

单例实例声明为 GetInstance 方法的静态变量,它是线程安全的吗? [复制]

*可以*为静态的C#方法应该是静态的吗? [关闭]

C#中在哪里声明全局变量啊,具体位置在哪儿,我是初学者。。。

不同的静态全局变量共享相同的内存地址

该功能应该是静态的吗?