2011-09-29 3 views
8

저는 스프링 빈을 선언했습니다. 스프링 빈은 내 이메일 서버를 매회 폴링합니다. 메일이있는 경우 메일을 가져 와서 첨부 파일을 추출하려고 시도합니다. 이 파일들은 안전하게 보관하는 업 로더에 제출됩니다. 업 로더는 Spring bean으로 선언됩니다. 세 번째 빈은 이메일의 보낸 사람을 파일의 파일 이름과 연관시켜 DB에 저장합니다.기본 빈 범위를 싱글 톤으로 설정하면 동시 호출이 발생할 때 나쁘지 않을까요?

몇 사람이 동시에 이메일을 보내려고 시도했을 때, 지저분한 일이 일어났습니다. DB의 레코드에 잘못된 파일 이름이 있습니다. 일부는 파일 이름을 전혀 얻지 못했습니다.

나는 기본적으로 bean의 범위를 singleton으로 지정했기 때문에 문제가 발생했다고 생각했습니다. 이것은 많은 스레드가 아마 하나의 동일한 인스턴스를 동시에 엉망으로 만들고 있음을 의미합니다. 문제는이를 해결하는 방법입니다.

모든 민감한 방법을 동기화하면 모든 스레드가 스택되어 서로 기다릴 수 있습니다. 이는 멀티 스레딩에 대한 전체적인 생각에 부합합니다. 콩을 범위 지정 한편

은 "요청"새로운 우리가 메모리 소비에 대해 얘기하면, 하나 정말 좋지 않아 그들 각각의 인스턴스 및 스레드 스케줄링 내가

을 만들려고합니다 혼란스러워. 어떻게해야합니까?

+0

하지만, 더 중요한 것은 ... 당신의 접근 방식을 재 방문 가치가있을 수도 있습니다 호출 된 메소드가 다른 스레드가 의존하는 인스턴스 데이터를 수정하지 않도록해야합니다. 코드를 제공하지 않았으므로 추측 만하고 있지만 단순한 메소드 동기화 이상의 의미 일 것입니다. 데이터를 덮어 쓰기 전에 체계적인 문제가있는 것처럼 보입니다. –

답변

8

@Bozho 및 @stivio 답변에 동의합니다.

선호되는 옵션은 단일 범위의 빈에 상태 저장을 전달하고 컨텍스트 개체를 메서드에 전달하거나 모든 처리주기마다 생성되는 프로토 타입/요청 범위 콩을 사용하는 것입니다. 동기화는 대개 이러한 접근 방법 중 하나를 선택하여 피할 수 있으며 교착 상태를 피하면서 훨씬 더 많은 성능을 얻을 수 있습니다. 정적 멤버와 같은 공유 상태를 수정하지 않도록하십시오.

는 각 방법에 대한 장점과 단점이 있습니다

  1. Singlton 콩 몇 가지 좋은 객체 지향 설계되지 않습니다 말할 수있는 서비스와 같은 클래스, 같은 행동이다.
  2. 긴 메소드 체인의 메소드에 컨텍스트를 전달하면주의하지 않으면 코드가 지저분해질 수 있습니다.
  3. 프로토 타입 빈은 의도 한 것보다 오래 메모리를 많이 차지할 수 있으며 메모리가 소모 될 수 있습니다. 이 콩의 수명주기에주의해야합니다.
  4. 프로토 타입 빈은 디자인을 더 멋지게 만들 수 있습니다. 콩을 여러 스레드로 재사용하지 않는지 확인하십시오.

나는 대부분의 간단한 경우에 서비스 접근 방식을 사용하는 경향이 있습니다. 또한 이러한 싱글 톤 빈이 계산을위한 상태를 유지할 수있는 처리 객체를 생성하도록 할 수 있습니다. 이것은보다 복잡한 시나리오에 가장 적합한 솔루션입니다.

편집 : 당신이 콩을 범위 프로토 타입에 따라 싱글 콩을 가지고 있고, 각 메소드 호출에 대한 프로토 타입 빈의 새로운 인스턴스를 할 때 경우가 있습니다 . Spring은이를위한 몇 가지 솔루션을 제공한다.

첫 번째는 Method Injection을 사용하고 있으며, 이는 Spring 참조 문서에 설명되어있다. 클래스를 추상화해야하므로이 접근 방식이 마음에 들지 않습니다.

두 번째는 ServiceLocatorFactoryBean 또는 사용자 고유의 팩토리 클래스 (종속성을 주입하고 생성자를 호출해야 함)를 사용하는 것입니다. 이 접근법은 대부분의 경우에 효과적이며 Spring과 연결되지 않습니다.

프로토 타입 bean이 런타임 종속성을 가지기를 원하는 경우가 있습니다. 좋은 친구가 여기에 좋은 게시물을 썼습니다 : http://techo-ecco.com/blog/spring-prototype-scoped-beans-and-dependency-injection/.

+0

포인트 1을 제외하고 나는 동의한다. 싱글 톤 빈은 단위 테스트를 더 어렵게 만들고 매직 의존성을 발생시키기 때문에 추천하지 않는다.하지만 우리는 자바 싱글 톤, 개인 생성자와 정적 메소드 인스턴스를 반환합니다. 스프링 싱글 톤에는 이러한 문제가 없습니다. – stivlo

+0

@stivio 싱글 톤 빈을 썼을 때 나는 싱글 톤 범위에서 스프링 빈을 의미했으며 싱글 톤 디자인 패턴을 구현하는 자바 클래스는 의미하지 않았다. 나중에 GoF 책에서 가장 문제가되는 패턴 인 것에 동의하지만, 싱글 톤 스프링 빈은 테스트하기가 어렵지 않습니다. 인스턴스화하고 인터페이스를 도입하고 의존성을 모방 할 수 있습니다. 다른 반원들처럼 시험해보십시오. –

+1

바로 그 말입니다. "스프링 싱글 톤에는 이러한 문제가 없습니다." - 그 이유는 1 점에 동의하지 않는 이유입니다. GoF 싱글 톤에 대해 이야기한다면 동의 할 것입니다. – stivlo

12

싱글 톤 범위의 bean은 어떤 상태도 보유해서는 안되며 일반적으로 문제를 해결합니다. 메서드 매개 변수로만 데이터를 전달하고 필드에 데이터를 할당하지 않으면 안전합니다.

2

그렇지 않으면 bean을 요청으로 선언하고, 메모리 소비에 대해 걱정하지 마십시오. 가비지 콜렉션은 메모리가 충분하면 성능상의 문제가되지 않을 것입니다.

+0

내 유일한 문제는 Spring Integration의 service-activator를 사용하여 메일을 폴링 중이므로 웹 요청이 아닌 메일 관리자의 "요청"범위를 만들 수 없다는 것입니다. MailManager를 "스레드 단위"로 표시 할 수 있습니까? – user802232

+0

"프로토 타입"을 사용하십시오. – stivlo

+0

빈을 스레드에 바인드하는 Spring 코어의 SimpleThreadScope (http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/context/support/SimpleThreadScope.html)를 사용할 수도 있습니다 -local –

1

싱글 톤은 상태가 좋고 스레드로부터 안전해야합니다.

싱글 톤이 상태 비 저장 인 경우, 상태가 유지되는 퇴보 한 사례이며 스레드 안전성은 아주 사실입니다. 그렇다면 싱글 톤의 핵심은 무엇입니까? 누군가가 요청할 때마다 새로운 것을 만드십시오.

인스턴스가 상태 저장이고 스레드로부터 안전하지 않으면 singleton이 아니어야합니다. 각 스레드는 독점적으로 다른 인스턴스를 가져야합니다.

+1

저는 스테이트 풀러 싱글 톤이 상당히 위험하다고 생각합니다 (사실 글로벌 변수입니다). 왜 당신은 싱글 톤이 stateful이어야한다고 생각합니까? – sleske

2

추상적으로 말하기 : 스프링 통합을 사용하는 경우 메시지 자체로 코드를 작성해야합니다. 예를 들어 중요한 모든 상태는 메시지와 함께 전파되어야합니다. 따라서 하중을 처리하기 위해 더 많은 Spring Integration 인스턴스를 추가하여 확장하는 것이 쉽습니다. Spring Integration의 유일한 상태 (정말로)는 aggregator와 같은 구성 요소를위한 것입니다.이 구성 요소는 교정이있는 메시지를 기다리며 수집합니다. 이 경우 MongoDB와 같은 백업 저장소에 위임하여 이러한 메시지의 저장소를 처리 할 수 ​​있으며 이는 물론 스레드로부터 안전합니다.

더 일반적으로 이것은 단계적 이벤트 기반 아키텍처의 예입니다. 구성 요소는 메시지를 처리하는 데 N (1) 개의 상태를 유지해야하며 알 수없는 다른 구성 요소에 의해 소비되도록 채널에 전달합니다 메시지가 나온 이전 구성 요소에 대해 당신이 봄 통합을 사용하여 스레드 안전 문제가 발생하는 경우

, 당신 의도 다르게보다 조금 무언가를 할 수 있으며

당신은 당신의 방법을 동기화해야
관련 문제