@Bean 에노테이션이나 @Component 에노테이션 과 같이 @Scope 에노테이션을 붙여 빈의 스코프를 결정 할 수 있다는 사실을 기억한다.
빈의 스코프는 기본이 Sington 이며 같은 레퍼런스를 갖는다,
하지만 @Scope 에노테이션의 속성값으로 webSocket, prototype, Session 등을 지정할 수 있다.
@Component
@Scope(value = "prototype")
public class Proto {
}
@Component
@Scope("singleton")
public class Single {
}
요렇게!
프로토 타입 빈은 매번 다른 인스턴스를 생성하며, 싱글톤 빈이 DEFAULT 값으로 언제나 같은 객체를 리턴한다.
prototype은 Thread-Safe하지 않다. 여기까지는 이야기가 간단하며, 프로토 타입 빈은 또한 스프링에서 생명주기를 전부 관리해주지 않게 된다.
문제는 두 가지 스코프를 같이 엮어 사용할때 발생한다는 점이다.
-
프로토 타입 스콮 빈에서 싱글톤타입 빈을 사용할 경우, 언제나 같은 객체를 이용하게 되므로 문제가 생기지않는다.
문제가 생기는 지점은 , , 싱글톤 스콮 빈이 프로토 타입 스콮 빈을 사용할 경우이다..
- 스프링 컨테이너 생명주기와 빈의 생명주기에 관계에 따라 스프링 컨테이너 구동 작업중에 빈의 생성과 의존성이 주입되는데, 여기서 싱글톤 타입의 빈은 값이 완성되므로, 안에 포함하는 값또한, 완성되어 고정된다는 점 에서 발생하는 문제이다.
즉 언제나 같은 객체의 레퍼런스가 튀어나와버린다.
package me.soomin.demospring51;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class AppRunner implements ApplicationRunner {
@Autowired
ApplicationContext ctx;
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println(ctx.getBean(Proto.class));
System.out.println(ctx.getBean(Proto.class));
System.out.println(ctx.getBean(Proto.class));// 프로토 타입 스콮 빈의 객체는 매번 다르다.
System.out.println("single");
System.out.println(ctx.getBean(Single.class));
System.out.println(ctx.getBean(Single.class));
System.out.println(ctx.getBean(Single.class));// 싱글톤 타입 스콮 빈의 객체참조는 매번 같다.
System.out.println("proto by single");
System.out.println(ctx.getBean(Single.class).getProto());
System.out.println(ctx.getBean(Single.class).getProto());
System.out.println(ctx.getBean(Single.class).getProto());
//싱글톤 스콮 빈이 내포하는 프로토 타입 스콮 빈은...매번 값이 ...같다.
}
}
이문제를 해결하는 방법은 @Scope 에노테이션의 속성인 proxyMode << 속성을 사용하는 방법이다.
@Component
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
// 클래스를 기반으로한 프록시로 감싸주어라 라는 속성
public class Proto {
}
ScopedProxyMode의 상수 값을 이용하여 프록시 사용여부를 지정하며 기본값은 ScopedProxyMode.DEFAULT이다
즉, 프록시를 사용하지않겠다는 의미이다
1. 빈이 인터페이스라면 ScopedProxyMode.INTERFACE , 클래스라면 ScopedProxyMode.TARGET_CLASS 를 사용하여 프록시 객체를 만들어 빈객체를 감싼다.
@Scope 에노테이션의 proxyMode 속성의 상수인 ScopedProxyMode.TARGET_CLASS 는 클래스 기반의 프록시로 해당 빈을 감싸주어라라는 의미이다. 즉 상속해서 만들어낸 프록시 객체를 거쳐서 prototype 빈에 접근 하라는 의미이다
* 이렇게 할 시에, 만들어지는 빈은 프록시 객체의 빈 이며, 주입되는 빈 또한 프록시 객체의 빈 이 된다.
핵심 내용 : 싱글톤 객체를 사용할때 prototype 빈이나 매번 생성되는 값이나 객체를 사용할 경우에 Thread - Safe 하지 않으므로, 멀티스레드 환경에서 값이 뒤죽박죽변할 수 있다.
싱글톤 객체의 인스턴스 멤버는 서로 같은 값을 참조 하게 되므로, 뒤죽박죽 엮여버린다.
'springframework' 카테고리의 다른 글
o.s.w IoC 핵심기술. @PropertySource (0) | 2020.08.20 |
---|---|
springframeworko.s.w IoC 핵심기술. @Profile (0) | 2020.08.20 |
Junit (0) | 2020.08.17 |
인텔리J 기반 스프링 프로젝트 생성 (0) | 2020.08.12 |
o.s.w IoC 핵심기술. @Component 와 @ComponentScan (0) | 2020.08.12 |