Spring에서 애플리케이션의 핵심을 이루는 객체들이며 Spring IoC 컨테이너에 의해 관리되는 객체들을 빈(Bean)이라고 한다. 빈은 Spring IoC 컨테이너에 의해 생성되고 조립되며 기타 관리된다.
Spring Bean은 쉽게 말해 Spring IoC 컨테이너가 관리하는 자바 객체라고 볼 수 있다.
이 때, Spring IoC 컨테이너가 맡은 역할은 다음과 같다.
빈의 생성: Spring IoC 컨테이너는 빈을 생성한다.
의존성 주입(Dependency Injection): 빈이 의존하는 다른 빈들을 주입한다.
빈의 생명주기 관리(Lifecycle Management): 빈의 생명주기를 관리한다.
스코프 관리(Scope Management): 빈의 스코프를 관리한다.
빈의 설정 변경 및 업데이트: 런타임 중에 빈의 설정을 변경하거나 업데이트할 수 있다.
빈의 후처리(Bean Post-processing): 빈이 생성된 후에 추가적인 작업을 수행할 수 있도록 지원한다.
Spring IoC 컨테이너가 Bean을 관리하기에 다음과 같은 장점이 있다.
Spring Bean은 Bean Definition이라는 인터페이스로 관리하여 Java, XML 등 여러 방식으로 정의할 수 있다.
Bean은 BeanDefinition으로 정의되고, BeanDefinition에 따라 활용하는 방법이 달라진다.
BeanDefinition 정보
Spring Bean을 등록하는 방법은 대표적으로 두 가지가 존재한다.
1. Java Configuration을 이용한 수동 빈 등록
@Configuration
어노테이션을 사용하여 Java Configuration 클래스를 만들고, @Bean
어노테이션을 사용하여 해당 메서드를 빈으로 등록할 수 있다.
@Configuration
public class MyConfiguration {
@Bean
public MyBean myBean() {
return new MyBean();
}
}
2. Component Scanning을 이용한 자동 빈 등록
@ComponentScan
어노테이션을 사용하여 패키지를 스캔하고, @Component
, @Service
, @Repository
, @Controller
등의 어노테이션을 사용하여 해당 클래스를 빈으로 등록할 수 있다.
Spring boot에서 @ComponentScan
어노테이션은 @SpringBootApplication
에 포함되어 있다.
@Component
public class MyComponent {
// Bean definition
}
Spring Container는 자바 객체(Bean)의 생성과 소멸 같은 생명주기(Life Cycle)를 관리하며, 생성된 자바 객체들에게 추가적인 기능을 제공하는 역할을 한다.
Bean의 Life Cycle이란 해당 객체가 언제, 어떻게 생성되어 소멸되기 전까지 어떤 작업을 수행하고 언제, 어떻게 소멸되는지 일련의 과정을 이르는 말이다.
Bean의 Life Cycle을 살펴보면 다음과 같다.
Spring Container는 빈 생성이나 소멸 시 호출될 수 있는 콜백 메서드를 다음과 같이 제공하고 있다.
@PostConstruct
, @PreDestroy
어노테이션1. InitializingBean, DisposableBean callback interfaces
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class DemoBean implements InitializingBean, DisposableBean
{
//Other bean attributes and methods
@Override
public void afterPropertiesSet() throws Exception
{
//Bean initialization code
}
@Override
public void destroy() throws Exception
{
//Bean destruction code
}
}
단점
인터페이스를 사용하는 초기화 및 종료 방법은 스프링 초창기에 나온 방법들이며, 지금은 거의 사용하지 않는다.
2. 설정 정보에 사용자 정의 초기화 메서드, 종료 메서드 지정
public class ExampleBean {
public void init() throws Exception {
//초기화 콜백
}
public void close() throws Exception {
// 소멸 전 콜백
}
}
@Configuration
class LifeCycleConfig {
@Bean(initMethod = "init", destroyMethod = "close")
public ExampleBean exampleBean() {
}
}
• 이는 수정할 수 없는 외부 클래스, 정확히 위의 두 인터페이스를 구현시킬 수 없는 클래스의 객체 스프링 컨테이너에 등록할 때 유용하다.
• 메소드 명을 자유롭게 부여할 수있고, 스프링 코드에 의존하지 않는다.
• 설정 정보를 사용하기 때문에 코드를 고칠 수 없는 외부 라이브러리에도 초기화, 종료 메서드를 적용할 수 있다.
3. @PostConstruct, @PreDestroy 어노테이션
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class DemoBean
{
@PostConstruct
public void customInit()
{
System.out.println("Method customInit() invoked...");
}
@PreDestroy
public void customDestroy()
{
System.out.println("Method customDestroy() invoked...");
}
}
• 최신 스프링에서 가장 권장하는 방법으로 애노테이션 하나만 붙이면 되므로 매우 편리하다.
• 패키지를 잘 보면 javax.annotation.PostConstruct 로 스프링에 종속적인 기술이 아니라 JSR-250 라는 자바 표준이다. 따라서 스프링이 아닌 다른 컨테이너에서도 동작한다.
• 유일한 단점은 외부 라이브러리에는 적용하지 못한다.
Bean의 scope는 해당 Bean의 생명주기와 사용되는 범위를 정의한다.
다음과 같은 6개의 scope가 존재한다.
Scope | Description |
---|---|
singleton (기본값) | 스프링 IoC 컨테이너당 하나의 인스턴스만 사용 |
prototype | 매번 새로운 빈을 정의해서 사용 |
request | HTTP 라이프 사이클 마다 한개의 빈을 사용, web-aware 컨택스트에서만 사용가능 - ex. Applicaiton context |
session | HTTP 세션마다 하나의 빈을 사용, web-aware 컨택스트에서만 사용가능 - ex. Applicaiton context |
application | ServeltContext 라이프사이클 동안 한개의 빈만 사용, web-aware 컨택스트에서만 사용가능 - ex. Applicaiton context |
websocket | websocket 라이프사이클 안에서 한개의 빈만 사용, web-aware 컨택스트에서만 사용가능 - ex. Applicaiton context |
Bean life cycle in Java Spring
Quick Guide to Spring Bean Scopes
Bean scopes