IT Share you

RestTemplate 스레드는 안전합니까?

shareyou 2020. 12. 12. 12:39
반응형

RestTemplate 스레드는 안전합니까?


Spring은 RestTemplate스레드로부터 안전합니까? 그건

  • A는 RestTemplate여러 개의 연결을 안전하게 공유 할 수있는 전략 객체. 또는
  • A는 RestTemplate사용 중에 공유 될 수있다 (데이터베이스 연결 등)를 접속 대상물, 각각의 연결에 대해 새롭게 생성을 요구하거나 풀링.

RestTemplate 스레드로부터 안전합니다 (강조 추가됨) :

개념적으로는 매우 비슷합니다 JdbcTemplate, JmsTemplate그리고 다양한 템플릿은 Spring 프레임 워크 및 기타 포트폴리오 프로젝트에서 발견. 예를 들어 는 일단 생성되면 스레드로부터 안전함을 의미합니다.RestTemplate


RestTemplate클래스의 객체는 HTTP를 처리하기 위해 상태 정보를 변경하지 않습니다. 클래스는 연결 객체와 같은 것이 아니라 전략 디자인 패턴의 인스턴스입니다. 상태 정보가 없으면 서로 다른 스레드가 RestTemplate개체 를 공유하는 경우 상태 정보를 손상 시키거나 경주 할 가능성이 없습니다 . 이것이 스레드가 이러한 개체를 공유 할 수있는 이유입니다.

소스 코드RestTemplate 를 살펴보면 객체 생성 후 스레드 안전성을 제공하기 위해 synchronized메서드 나 volatile필드를 사용하지 않는 것을 알 수 있습니다 . 따라서 시공 후 개체 를 수정하는 것은 안전 하지 않습니다RestTemplate . 특히 메시지 변환기를 추가하는 것은 안전하지 않습니다.

메시지 변환기 목록을 제공하려면 다음 중 하나를 수행해야합니다.

  • RestTemplate(List<HttpMessageConverter<?>> messageConverters)생성자를 사용하십시오 . 의 내부 목록으로 messageConvertersIS final,이 안전하게 메시지 컨버터의 목록을 게시합니다 .
  • 사용 setMessageConverters(List<HttpMessageConverter<?>> messageConverters)뮤 테이터를 하고 다음 안전하게 게시 변경된 RestTemplate개체를. 대부분의 실제 사용 사례에서 컨테이너설정하는 스레드에 의해<property name="messageConverters"><list>... 빈이 안전하게 게시 되므로이 작업을 수행 하는 Spring 빈 정의를 사용합니다.
  • List.add에서 반환 한 참조에 사용 getMessageConverters()하고 변경된 RestTemplate개체 를 안전하게 게시 합니다. 그러나에 대한 설명서 RestTemplate는 메시지 변환기 목록을 변경하는 데 사용할 수있는 참조를 반환한다고 명시 적으로 설명 하지 않습니다. 현재 구현은 수행하지만 Collections.unmodifiableList목록 또는 복사본 을 반환하도록 구현이 변경 될 수 있습니다 . 따라서 이렇게 변경하지 않는 것이 좋습니다.

첫 번째 경우는 개체를 구성 할 때 메시지 변환기를 설정하는 유일한 방법이므로 "구성된 후에는 스레드로부터 안전합니다"라고 말하는 것이 옳습니다.

클래스는 Spring Framework의 일부이므로 거의 모든 실제 사례에서 클래스의 객체는 첫 번째 (생성자를 사용한 종속성 주입) 또는 두 번째 (세터를 사용한 종속성 주입)를 사용하여 Spring Application Context의 일부로 설정됩니다. 여러 스레드에 안전하게 게시 될 수 있습니다.


라이브러리의 관점에서 스레드로부터 안전합니다. 예를 들어, getMessageConverters ()는 public입니다. 즉, 누군가가 목록을 보유하고 라이브러리의 목적을 벗어나 수정하면 문제가 발생합니다 (ResTemplate 인스턴스화 후 언제든지 호출되는 경우 setter 메서드까지도). -그리고 분명히 다른 스레드에서 사용되는 동안 붐!). 아마도 로스에게 일어난 일일 것입니다 (답변에 대한 평판이 충분하지 않지만 스레드 안전 인수가 아닌 스레드 안전 인수를 모두 백업하고 있습니다)


좋아, 이러한 문제를 일으킨 소스 제어에서 이전 코드를 파낼 수는 있지만.

생성시 동기화를해도 다른 스레드가 내부 컬렉션을 수정할 수있는 상황이 존재한다고 말하는 것이 타당하다고 생각합니다. 그러니 조심하세요. 예전 코드를 보면 실제로 메시지 변환기를 사용하고있었습니다. 그러나 생성시 동기화 된 경우에만.

restTemplate = new RestTemplate();

restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());

그 후 RestTemplate과의 유일한 상호 작용은 다음과 같습니다.

return restTemplate.postForObject(url, object, clazz);

이것은 결국 예외를 발생시키는 줄이기도합니다.

물론 메시지 변환기와의 상호 작용은 없습니다 (로컬 참조가 없음).

스택 트레이스와 스프링 소스 코드를 살펴보면 다음 줄에서 오류가 발생했습니다.

for (HttpMessageConverter<?> converter : getMessageConverters()) {

그래서 우리는 무엇을 가지고 있습니까?

  1. messageConverters에 대한 동시 액세스 권한이 있습니다.
  2. 우리 코드가 그것을하지 않았다면 어떤 코드가 그랬습니까? 대답이 없습니다. 당시 내 솔루션은이 앱에서 성능이 문제가되지 않았기 때문에 매번 새로운 RestTemplate을 만드는 것이 었습니다.

요약하자면, 스레드로부터 안전하지 않은 상황이있을 수 있습니다. 메시지 변환기를 직접 사용한다면 확실히 그렇습니다. 이 사건은 이상하지만 게시하는 것이 유용 할 것이라고 생각했습니다.


위의 수락 된 답변에 동의하지 않는 것이 싫지만 (강조 추가됨) 스레드로부터 안전하지 않습니다. 창조 후에도. 내부적으로 그것은 ArrayLists를 가지고 놀고 있으며 소스를 파지 않았습니다. 나는 이것들을 너무 많이 보았다 :

java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at org.springframework.web.client.RestTemplate$AcceptHeaderRequestCallback.doWithRequest(RestTemplate.java:677)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:567)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:545)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:253)

참고 URL : https://stackoverflow.com/questions/22989500/is-resttemplate-thread-safe

반응형