스프링 빈은 Thread safe 하나,
스프링 빈 내에서의 멤버변수는 Thread safe 하지 않다.
--> race condition 을 유의해야 한다.
--> stateless 하게 개발해야 한다.
※ race condition :
두 개 이상의 프로세스가 공통 자원을 병행적으로(concurrently) 읽거나 쓸 때,
공용 데이터에 대한 접근이 어떤 순서에 따라 이루어졌는지에 따라 그 실행 결과가 달라지는 상황을 말한다.
※ stateful :
상태 변화에 의존적인 상태를 의미.
ex)서버 session 은 stateful, 클라이언트가 토큰을 들고있는 방식은 stateless (공부중)
[Example]
1
2
3
4
5
6
7
8
9
10
11
|
@Service
public class TestServiceImpl implements TestService {
private int idx = 0;
@Override
public void test(){
System.out.println("idx : " + idx);
idx++;
}
}
|
cs |
ControllerA 에서 TestService를 주입받아 test() 메소드 실행시 idx 값이 호출될 때마다 증가하며,
ControllerB 에서도 TestService를 주입받아 test() 메소드 실행시 idx 값이 호출될 때마다 증가함을 확인 할 수 있다.
만약 멤버변수를 단순 읽기 전용으로 사용한다면 문제되지 않지만, 위와 같이 읽기 뿐만 아닌 쓰는 용도로 사용한다면 문제가 된다.
이처럼 스프링 Bean 은 Default로 싱글톤 디자인패턴을 따르므로,
멤버변수에 값을 저장(쓰는 행위)하는 식의 stateful한 설계는 피해야 한다.
(가급적 스프링 빈으로 관리되는 객체만 멤버변수로 사용하는게 좋다)
[코드 개선]
위와 같은 코드는 멤버변수를 제거하고, 메소드 내에서 지역변수로 선언 및 파라미터로 값을 들고 다니는 방식으로 수정을 하거나(권장), 빈의 scope 를 prototype 으로 주어 호출시마다 새로운 인스턴스를 생성하도록 해야 한다.
@Scope("prototype") annotation 을 class 선언 부에 달아주면 해당 객체는 싱글톤이 아닌 프로토타입 객체가 된다.
※ 싱글톤 빈 내에서 프로토타입 빈 생성을 할 경우 정상적으로 프로토타입 빈 동작이 되지 않는다(호출마다 빈이 생성되야 하나 그렇지 못함)
[prototype Scope를 적용한 코드]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
@Service
@Scope("prototype")
public class TestServiceImpl implements TestService, InitializingBean, DisposableBean {
private int idx = 0;
@Override
public void test(){
System.out.println("idx : " + idx);
idx++;
}
@Override
public void afterPropertiesSet() throws Exception {
logger.info("created service! ");
}
@Override
public void destroy() throws Exception {
logger.info("destroyed service! ");
}
}
|
cs |
※ InitializingBean, DisposableBean 인터페이스의 afterPropertiesSet(), destroy() 메소드는 빈이 생성, 제거 될 때 각각 호출된다.
코드를 위와 같이 수정한 후, 이전과 동일하게
1) ControllerA 에서 TestService를 주입받아 test() 메소드 실행,
2) ControllerB 에서도 TestService를 주입받아 test() 메소드 실행한 경우 결과는 아래와 같다.
[실행 결과]
created service!
idx : 0
created service!
idx : 1
참고:
토비의 스프링 3.1(도서)
https://gmlwjd9405.github.io/2018/11/10/spring-beans.html
https://gmlwjd9405.github.io/2018/11/10/spring-beans.html
'back > Spring Framework' 카테고리의 다른 글
[Spring Fw] 스프링프레임워크에서 JUnit 을 이용한 API 테스트 : Spring Framework + JUnit + JNDI (0) | 2019.12.30 |
---|---|
[log4j] log4j.xml 설정 : Logger 위계구조, 로그 분리하기 (0) | 2019.12.19 |
[Spring Fw] component-scan vs annotation-driven vs annotation-config (0) | 2019.12.06 |
[Spring Fw] Spring property 설정 (0) | 2019.08.27 |
[Spring fw] Transaction 설정 및 주의사항 : 예상치 못한 롤백이 이루어 지는 경우, 롤백이 되지 않는 경우 확인해봐야 할 것 (1) | 2019.08.04 |