싱글톤
스프링에서 Scope에 대한 설정을 하지 않고 Bean 등록을 하게 되면 싱글톤으로 등록이 됩니다. 이 경우에는 하나의 bean을 사용하게 됩니다.
테스트용으로만 사용 할 Library 클래스입니다.
1 2 3 4
| @Component public class Library {
}
|
동일한지 테스트 코드를 실행해 봅니다. 정상 실행이 되는 것을 확인할수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class TestControllerTest {
@Test public void test() { ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanConfig.class); Library library1 = (Library) ctx.getBean("library"); Library library2 = (Library) ctx.getBean("library");
System.out.println(library1); System.out.println(library2); assertEquals(library1, library2); } }
|
1 2
| kr.co.spring.Library@6293abcc kr.co.spring.Library@6293abcc
|
프로토타입
프로토타입으로 설정을 하는 경우 사용할때 마다 새로운 객체를 받습니다. 사용하는 방법은 프로토타입으로 사용할 객체 위에 @Scope("prototype")
를 추가해주면 됩니다.
1 2 3 4 5
| @Component @Scope("prototype") public class Library {
}
|
동일한 테스트 코드를 실행했을때 이번에는 두개의 객체가 서로 다르다를 에러가 발생하엿습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class TestControllerTest {
@Test public void test() { ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanConfig.class); Library library1 = (Library) ctx.getBean("library"); Library library2 = (Library) ctx.getBean("library");
System.out.println(library1); System.out.println(library2); assertEquals(library1, library2); } }
|
1 2 3 4 5 6
| kr.co.spring.Library@2133814f kr.co.spring.Library@4c15e7fd
java.lang.AssertionError: Expected :kr.co.spring.Library@2133814f Actual :kr.co.spring.Library@4c15e7fd
|
싱글톤 타입에서 프로토 타입 의존주입
프로토타입 bean에서 싱글톤타입의 bean을 의존주입 받아서 사용할때는 아무런 문제가 발생하지 않습니다. 하지만 반대의 경우에는 개발자의 의도와는 다른 결과를 발생시킬수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <!-- SingletonBean --> @Component public class SingletonBean { @Autowired PrototypeBean prototypeBean;
public PrototypeBean getPrototypeBean() { return prototypeBean; } }
<!-- PrototypeBean --> @Component @Scope("prototype") public class PrototypeBean {
}
|
1 2 3 4 5 6 7 8 9 10 11
| public class TestControllerTest {
@Test public void test() { ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanConfig.class); SingletonBean singletonBean = (SingletonBean) ctx.getBean("singletonBean");
System.out.println(singletonBean.getPrototypeBean()); System.out.println(singletonBean.getPrototypeBean()); } }
|
1 2
| kr.co.spring.PrototypeBean@37918c79 kr.co.spring.PrototypeBean@37918c79
|
위의 결과를 보았을때 프로토타입으로 Scope를 설정했지만 동일한 객체인것을 확인 할수 있습니다.
해결방법1. 프록시객체를 의존주입하기
@Scope 어노테이션에 프록시 설정을 하여 해당 프로토타입 빈을 감싸는 프록시 객체를 반환하는 방식을 사용하여 해결할수 있습니다.
1 2 3 4 5
| @Component @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS) public class PrototypeBean {
}
|
1 2
| kr.co.spring.PrototypeBean@28eaa59a kr.co.spring.PrototypeBean@3427b02d
|
해결방법2. ObjectProvider 사용
프로토타입 bean을 의존주입 받을 때 ObjectProvider<타입>을 사용 할수 있습니다. 실제 bean을 사용할 때는 getIfAvailable메소드를 이용합니다.
1 2 3 4 5 6 7 8 9
| @Component public class SingletonBean { @Autowired ObjectProvider<PrototypeBean> prototypeBean;
public PrototypeBean getPrototypeBean() { return prototypeBean.getIfAvailable(); } }
|
1 2
| kr.co.spring.PrototypeBean@222114ba kr.co.spring.PrototypeBean@3d121db3
|
위의 방법의 경우에는 스프링 클래스를 사용하기 때문에 스프링에 의존이 되어 첫번째 방법을 추천.