카테고리 없음
IoC 컨테이너와 빈(2) - 빈의 스코프
레알윙
2020. 3. 16. 23:10
반응형
빈의 스포크
싱글톤
애플리케이션 전반에 걸쳐서 해당 빈의 인스턴스가 1개뿐
@Service
public class Proto {
@Autowired
private Single single;
public Single getSingle() {
return single;
}
public void setSingle(Single single) {
this.single = single;
}
}
@Service
public class Single{
}
@Controller
public class HomeController {
@Autowired
Proto proto;
@Autowired
Single single;
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
System.out.println(single);
System.out.println(proto.getSingle());
System.out.println(single);
return "home";
}
}
프로토타입
매번 새로운 인스턴스를 만들어서 사용
- Request
- Session
- WebSocket
@Service
@Scope("prototype")
public class Proto {
}
@Service
public class Single{
}
@Controller
public class HomeController {
@Autowired
ApplicationContext ctx;
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
System.out.println("proto");
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));
return "home";
}
}
프로토타입 빈이 싱글톤 빈을 참조시
싱글 인스턴스는 매번 같은 인스턴스를 가져오기 때문에 아무 문제 없음
@Service
@Scope("prototype")
public class Proto {
@Autowired
Single single;
}
싱글톤 빈이 프로토타입 빈을 참조하면?
프로토타입 빈이 업데이트가 되어야 되는데 업데이트가 안된다.
@Service
@Scope("prototype")
public class Proto {
@Autowired
Single single;
}
@Service
public class Single{
@Autowired
private Proto proto;
public Proto getProto() {
return proto;
}
}
@Controller
public class HomeController {
@Autowired
ApplicationContext ctx;
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
System.out.println("proto");
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());
return "home";
}
}
이유 및 해결 방안
- 아래 코드를 설명하면 class기반의 빈을 프록시를 감싸서 그 프록시 빈을 사용하게 해라라고 설정
- 직접 사용하게 된다면 매번 프록시를 바꿔줘야되는데 매번 바꿔줄 수 없기 때문에 proxy를 상속받는 클래스를 만들어서 사용
- CG라이브러리기반에 클래스를 상속받아 프록시를 만들게 한다.
- 다이나믹 프록시(JDK)는 인터페이스의 프록시밖에 만들지 못한다.
scodped-proxy
proxyMode = ScopedProxyMode.TARGET_CLASS
@Scope 어노테이션에 proxyMode 사용 - 백기선님이 추천함
// CG라이브러리를 상속받는 프록시 사용
@Component @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class Proto {
}
// 다이내믹 프록시 사용(JDK)
@Component @Scope(value = "prototype", proxyMode = ScopedProxyMode.INTERFACES)
public class Proto {
}
Object-Provider
@Component @Scope(value = "prototype")
public class Proto {
}
@Service
public class Single{
@Autowired
private ObjectProvider<Proto> proto;
public Proto getProto() {
return proto.getIfAvailable();
}
}
@Controller
public class HomeController {
@Autowired
ApplicationContext ctx;
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
System.out.println("proto");
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());
return "home";
}
}
반응형