진짜 개발자
본문 바로가기

FrameWork/Spring

Spring - IoC 컨테이너의 기능 - 1 (Bean의 Scope)

728x90

이번 시간에는 Bean의 Scope에 대해 자세히 알아보도록 하겠습니다. AOP, MVC를 포스팅하다가 갑자기 왜 다시 IoC 컨테이너에 관련해서 포스팅을 하냐면.. 제 얕은 지식으로 각각의 파트들이 끝난줄 알았지만, 공부를 할 수록 더 많은 것을 알게되면서 더 많은 정보를 포스팅 해야겠다는 생각이 들어서 입니다. 

 

 

1. Bean의 Scope이란?

Bean의 Scope은 Bean의 생성방식을 결정하는 것입니다. 예를 들자면 Scope에 따라서 Bean이 Application당 1개만 생성되거나, 필요할 때마다 새로 생성을 한다던지 하는 그런한 방식을 의미합니다.

 

 

2. Bean의 Scope 종류

2.1 Singleton

어디서 많이 들어보셨을 것입니다. 저는 디자인 패턴을 공부하면서 먼저 접하게 되었던 단어 입니다. 간단히 말씀드리자면 어플리케이션이 동작하는동안 단 한개만 만들어진다는 의미입니다. Spring에서의 Bean들은 별도의 설정이 없다면 기본적으로 Singleton으로 생성이 됩니다. 즉, 지금까지 생성했던 Bean들은 모두 Singleton으로 주입이 되었던 것입니다. 예제를 통해 조금 더 자세히 알아보겠습니다.

 

 
 
 
 

바로 위 Bean의 Scope이 Singleton 입니다.

 

 
 
 
 

테스트를 위해서 하나의 Class를 더 생성했습니다. Test Class에서는 Single 객체를 @Autowired어노테이션을 통해 주입을 받습니다. getSingle()메소드를 가지고 있군요.

 

 
 
 
 

실행을 위한 runner Class입니다. 앞서 생성한 Single, Test Class를 @Autowired어노테이션을 통해 주입받고 있습니다. 실행시에는 주입받은 Single객체를 출력하고, 주입받은 test객체를 통해 single을 얻어와 또 출력하도록 했습니다. 결과는?

 

네, 당연히 두 경우 모두 같은 객체를 출력하는 것을 볼 수 있습니다.

 

 

2.2 Prototype

다음은 Prototype Scope입니다. Prototype의 경우에는 Bean을 IoC컨테이너로 부터 받아올 때마다 매번 새로운 객체를 생성하게 됩니다. 역시 예제를 통해 알아보도록 하겠습니다.

 

 
 
 
 

Prototype Scope을 가지는 Proto Class 입니다. 클래스 상단에 @Component 어노테이션 이외에 @Scope("prototype") 어노테이션을 부여해 Scope를 Prototype으로 지정했습니다.

 

 
 
 
 

Single Class입니다. Proto 객체를 주입받고, 그 객체를 리턴해주는 getProto() 메소드를 가지고 있습니다.

 

 
 
 
 

테스트를 위한 Runner Class 입니다. Single에서 주입 받도록한 Proto외 또 하나의 Proto 객체를 주입받는 것을 볼 수 있습니다. AppRunner Class에서 주입받은 proto와 Single Class 에서 주입받은 proto를 출력 해보도록하겠습니다.

 

결과는? 네, 서로 다른 객체가 생성되어 출력된것을 볼 수 있습니다. 이처럼 Prototype은 IoC컨테이너에 의해 Bean을 주입을 받을 때 마다 새로운 객체가 생성됩니다.

 

 
 
 
 

여기서 주의할 점은 같은 곳에있는 객체를 계속 호출한다고해서 계속해서 객체가 새로 생겨난다는 의미가 아닌것 입니다.

 

위의 결과는 당연히 같은 객체가 찍히겠죠?

 

 
 
 
 

위의 결과는 어떨까요?

 

네, 모두 다른 객체가 출력되는 것을 볼 수 있습니다. 바로 IoC 컨테이너로 부터 Bean을 가져올때마다 새로운 객체가 생성되기 때문이죠.

 

 

2.2.1 Singleton Scope안의 Prototype Scope

Prototype Scope을 사용하실때에는 Singleton Scope안에 주입되는 Prototype Scope을 주의하여 사용해야 합니다. 무슨말이냐구요? 예제를 보도록하죠.

 

 
 
 
 

우선 Proto Class는 매번 새로운 객체를 주입 받기 위해 prototype의 Scope를 가지도록 했습니다.

 

 
 
 
 

Single Class의 경우에는 아무런 Scope을 지정하지 않았으므로 Singleton Scope을 기본으로 가지게 됩니다. 또한, Proto 객체를 주입받고, 그것을 리턴하는 메소드를 만들었군요. 문제는 여기서 발생합니다. 우선 한번 실행 해보도록 하겠습니다.

 

 
 
 
 

어?, proto의 경우에는 IoC 컨테이너에 의해 Bean을 주입을 받을때마다 새로운 객체가 생성된다고 하지 않았냐구요?

 

잘 생각해보아야 합니다. single에 IoC 컨테이너가 Bean을 주입해줄 때 single의 필드에 존재하는 Proto에 또 주입이 되고 있는 형태입니다. 이때 proto는 Prototype이지만 single은 Singleton입니다. 즉 Single안에 존재하는 Proto는 새로 Bean이 생성되는 일이 없다는 것이죠.

다시 한번 말씀드리자면, Proto는 IoC Container로 부터 해당 빈을 요청할때마다 새로운 빈을 반환하는 scope입니다. 하지만, Single내에 한번 주입이 되고 난 이후에는, IoC Container로 부터 빈을 받아오는것이 아니므로 새로 생성되지 않습니다.

 

해결방법

1. Proxymode 사용

 
 
 
 

간단히 말씀드리면, proto의 @Scope 어노테이션 안에 proxyMode를 추가하면 됩니다.

 

 
 
 
 

이렇게 된다면 위의 proto안에 Proto를 감싸고 있는 Proxy객체가 주입되게 됩니다. Proto를 감싸는 Proxy는 자동으로 Proto를 상속받아 생성되므로 Proto타입의 참조변수 안에 주입이 가능해지게 됩니다.

 

결국에는, Single안의 Proto의 경우는 Proxy에 의해 새로운 객체들이 생성되어 출력되는 것을 볼 수 있습니다. 이게 어떻게 가능할까요?

 

바로 Single안의 Proto의 참조를 하는 경우 Proxy를 통해 참조하도록 하여 새로운 객체를 돌려주도록 하는 것입니다. 왜 Proxy로 감싸야할까요? 반대로 한번 생각해보면 간단합니다.

 

Single안에 있는 Proto를 직접 참조하게 된다면 중간에 Spring이 개입하여 새로운 객체를 반환하도록 할 수 있는 개입의 여지가 아예 없기 때문입니다.

 

 

2.3 이밖에 Scope..

이밖에 Scope들은 잘 사용되지 않는다고 합니다. 죄송하게도 필요시에는 찾아보시길..