Bean
빈(Bean)이란 Spring의 IoC 컨테이너에서 의존성을 주입하기 위해 내부적으로 생성하는 객체를 말한다. 이렇게 컨테이너에서 의존성을 관리해주기 때문에 제어가 역전(IoC - Inversion of Control) 되었다고 하며 개발자가 직접 의존성 객체를 생성하고 주입해주지 않아도 되기 때문에 개발 과정이 간편해지는 장점이 있다.
빈을 등록하는 방식에는 @Component
어노테이션과 @Bean
어노테이션으로 등록하는 방법 두가지가 있다.
@Component는 클래스
에서 사용가능하며 프레임워크에서 인스턴스를 생성한 후에 빈으로 등록 하도록 맡기는 방식이고,
@Bean은 메소드
에서 사용가능하며 개발자가 생성할 인스턴스를 직접 설정하고 메소드의 return을 통해 내보낸 것을 프레임워크에서 관리하도록 맡기는 방식이다.
1) @Component 어노테이션으로 등록
1
2
3
4
@Component
public class MyComponent {
...
}
웹 어플리케이션을 구현하다 보면 흔히 사용하는 @Controller
, @Service
어노테이션도 내부적으로 @Component 어노테이션이 포함되어 있기 때문에 빈으로 등록된다.
빈으로 등록할 컴포넌트를 찾는 조건의 설정은 @ComponentScan
어노테이션을 통해 설정할 수 있다.
스프링부트 프로젝트를 생성하면 메인 클래스에 @SpringBootApplication
어노테이션이 붙어있는 것을 볼 수 있는데, 해당 어노테이션 내부에 @ComponentScan 어노테이션이 포함되어 있다.
2) @Bean 어노테이션으로 등록
@Bean 어노테이션은 @Component와 달리 메소드에 붙인다. 그리고 이 메소드는 @Configuration
어노테이션이 붙어서 설정 파일 역할을 하는 클래스 내부에 등록되어야 한다.
1
2
3
4
5
6
7
@Configuration
public class MyConfiguration {
@Bean
public MyBean myBean() {
return new MyBean();
}
}
@SpringBootApplication 어노테이션에는 @Configuration 어노테이션 역시 내부적으로 포함되어 있기 때문에 메인 클래스에서도 빈 등록 설정을 할 수 있다.
Bean Scope
빈의 Scope 종류는 아래와 같으며, Singleton
과 Prototype
을 주로 사용한다고 한다. (둘 중에서도 대부분 Singleton 타입으로 사용한다고 한다.)
기본값은 Singleton 이다.
Scope | Description |
---|---|
singleton | (Default) Scopes a single bean definition to a single object instance for each Spring IoC container. |
prototype | Scopes a single bean definition to any number of object instances. |
request | Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext . |
session | Scopes a single bean definition to the lifecycle of an HTTP Session . Only valid in the context of a web-aware Spring ApplicationContext . |
application | Scopes a single bean definition to the lifecycle of a ServletContext . Only valid in the context of a web-aware Spring ApplicationContext . |
websocket | Scopes a single bean definition to the lifecycle of a WebSocket . Only valid in the context of a web-aware Spring ApplicationContext . |
Prototype Bean 생성
싱글톤 빈은 말 그대로 객체를 하나만 생성해놓고 재사용 하는 것을 말한다. 하나의 객체를 재사용하기 때문에 싱글톤의 단점을 그대로 가지고 있다. (멀티 스레드 환경에서 동시성 문제 같은)
프로토타입 빈은 싱글톤 빈과 달리 의존성을 주입할 때 새로운 객체를 생성하여 주입해주는 방식이다. 만약 개별 적으로 어떤 상태 값을 관리해야 한다면 싱글톤 빈보다 프로토타입 빈을 사용하는 것이 좋을 수 있다.
빈의 스코프를 재설정 하고 싶다면 @Scope
어노테이션을 사용하면 된다.
사용할 Scope를 스트링으로 입력해주어도 되지만 ConfigurableBeanFactory
인터페이스에 선언된 상수값을 사용할 수도 있다.(이 경우에는 singleton과 prototype 두 경우만 사용가능)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//@Component
@Component
@Scope("prototype") //또는 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class MyComponent {
...
}
//@Bean
@Configuration
public class MyConfiguration {
@Bean
@Scope("prototype")
public MyBean myBean() {
return new MyBean();
}
}
주의할 점
싱글톤 빈에 프로토타입 빈을 주입하는 경우 프로토타입 빈의 동작에 문제가 발생한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//SingletonBean
@Component
public class SingletonBean {
private PrototypeBean prototypeBean;
public SingletonBean(PrototypeBean prototypeBean) {
this.prototypeBean = prototypeBean;
}
public String toStringPrototypeBean() {
return prototypeBean.toString();
}
}
//PrototypeBean
@Component
@Scope(scopeName = "prototype")
public class PrototypeBean {
...
}
//print
@Test
void proxyTest() {
for (int i = 0; i< 3; i++) {
System.out.println(ctx.getBean(SingletonBean.class).toStringPrototypeBean());
}
}
이 경우에는 프로토타입 빈을 참조하더라도 같은 인스턴스를 참조하게 되는데, 프로토타입 빈의 Scope에 ProxyMode
를 설정하면 매번 새로운 인스턴스를 참조하도록 만들 수 있다.
1
2
3
4
5
6
@Component
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class PrototypeBean {
...
}