스프링 빈(Spring Bean)
- 스프링 빈이란 스프링 빈 컨테이너가 관리하는 순수 자바 객체(POJO)를 의미한다.
- 그렇다면 여기서 순수 자바 객체란 무엇인가?
순수 자바 객체의 정의는 Getter와 Setter만으로 이루어진 자바 객체를 뜻한다. 하지만 내가 이해한 스프링에서의 순수 자바 객체는,
다른 외부 요소에 영향을 받지 않는 객체지향적으로 설계된 자바 객체라고 이해하였다.
- 다시 말하면 그냥 스프링 컨테이너에서 사용하는 객체를 말하는 것이다.
스프링 애플리케이션 시작 과정
1. 스프링 빈 컨테이너 구현체(ConfigurableApplicationContext)가 설정파일(Java Config, Xml Config)를 로딩한다.
2. 설정에 정의된 빈 정의를 로딩하고, 지정된 위치에 있는 클래스들을 스캔하여 빈 정의로 등록한다.
3. 로딩을 마치면 스프링 빈 컨테이너는 빈을 생성하고 관리한다.
4. 의존성이 있는 빈들을 조립한다.
5. 빈 컨테이너 구현 클래스에 따라 추가작업을 한다.
6. 스프링 어플리케이션 실행 준비를 완료한다.
스프링 빈을 정의하는 방법
1. 자바 설정 클래스에서 @Bean으로 등록한다.
@Bean(name = "priceUnit")
public PriceUnit dollarPriceUnit() {
return new PriceUnit(Locale.US);
}
- 위와 같이 자바 객체를 바로 @Bean 어노테이션을 통하여 스프링 컨테이너에 등록 할 수 있다.
- 자바 설정 클래스(@Configuration 등) 아래에 등록해야 스프링 컨테이너에서 읽을 수 있다.
2. 스테레오 타입 애너테이션(@Component, @Controller 등)을 사용하여 클래스에 직접 정의한다.
@Component
public class LocaleDateTimeFormatter implements Formatter<LocalDateTime> {
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
// LocalDateTime 객체를 받아 내가 지정한 DateTimeFormat으로 변경
@Override
public String of(LocalDateTime target) {
return Optional.ofNullable(target)
.map(formatter::format)
.orElse(null);
}
}
- 기본적으로 SpringApplication.run()이 구동되는 클래스에 @SpringBootApplication에 포함된 @ComponentScan은,
그 하위 패키지에 있는 모든 클래스들에 대한 컴포넌트들을 찾아 빈으로 자동으로 등록해준다.
- 그러므로, 메인 클래스 하위에 만드는 모든 컴포넌트들은 @Component, @Service 등의 어노테이션만 달아주면 알아서 빈으로 등록된다.
3. BeanDefinition 인터페이스를 구현하여 정의한다.
4. XML 설정 방식을 사용하여 정의한다.
스프링 컨테이너(ApplicationContext)
public interface ApplicationContext extends
EnvironmentCapable, ---1
ListableBeanFactory, ---2
HierachicalBeanFactory, ---3
MessageSource, ---4
ApplicationEventPublisher, ---5
ResourcePatternResolver ---6
- 스프링 빈을 생성하고 의존성을 관리하는 BeanFactory 인터페이스 기능에 여러가지 부가적인 기능을 더한 것이 스프링 부트에서 사용하는 ApplicationContext이다.
위와 같은 인터페이스들을 상속하며 간단히 설명하면 다음과 같다.
1. 환경 변수 설정에 관련된 Environment 객체를 제공하는 인터페이스
2. 스프링 빈 리스트를 리턴 하는 메서드를 제공하는 인터페이스
3. 빈들의 부모-자식 관계를 맺고 그에 관련된 메서드를 제공하는 인터페이스
4. 국제화 메시지를 처리할 수 있는 메서드를 제공하는 인터페이스
5. 스프링 프레임워크에서 사용할 수 있는 이벤트들을 생서하는 메서드를 제공하는 인터페이스
6. 패턴을 이용하여 리소스를 다룰 수 있게 하는 메서드를 제공하는 인터페이스
스프링 빈의 스코프
- 자바의 객체는 사용자가 new 키워드로 생성하고, 사용이 끝나면 가비지 컬렉터가 알아서 소멸해준다.
하지만 스프링에서는 위에서 설명한 스프링 컨테이너(ApplicationContext)가 빈들을 생성하고 소멸시키는데, 빈의 생명주기에 대한 설정은 다음과 같다.
1. Singleton : 기본값, 컨테이너에서 단 하나만 생성하고 하나의 객체를 여러곳에 주입한다. 컨테이너와 같이 생성 후 컨테이너와 같이 소멸
2. Prototype : 컨테이너에서 여러개를 생성하여, 의존성을 주입할 때 마다 새로운 객체를 주입한다.
3. Request : 웹 기능 한정, HTTP 요청을 처리할 때 마다 새로운 객체를 생성한다.
4. Session: 웹 기능 한정, HTTP 세션과 대응하는 새로운 객체를 생성한다.
5. Application : 웹 기능 한정, Servlet 컨텍스트와 대응하는 새로운 객체를 생성한다.
6. WebSocket : 웹 기능 한정, Web Socket 세션과 대응하는 새로운 객체를 생성한다.
스프링 빈의 생명주기
스프링 빈의 생명주기는 다음과 같다.
스프링 빈 정의 로딩 -> 스프링 빈 정의 후 처리 -> 스프링 빈 초기화 -> 의존성 주입 -> 초기화 후 스프링 빈에 정의된 CallBack 실행 -> 사용가능한 스프링 빈 상태 -> 스프링 빈 컨테이너 종료 -> 파기 전 스프링 빈에 정의된 CallBack 실행
- BeanPostProcessor 인터페이스 정의, @PostConstruct 어노테이션 사용 등으로 스프링 빈 생성 후 실행할 콜백 함수를 정의할 수 있다.
- @PreDestroy 어노테이션, DisposableBean 인터페이스 정의 등으로 스프링 컨테이너 종료 후, 스프링 빈 삭제 전 실행할 콜백 함수를 정의 할 수 있다.
스프링 빈 생성 시간 설정
1. @Primary 애너테이션
@Bean
@Primary
public PriceUnit primaryPriceUnit() {
return new PriceUnit(Locale.US);
}
@Bean
public PriceUnit secondaryPriceUnit() {
return new PriceUnit(Locale.KOREA);
}
- 같은 타입인 PriceUnit의 빈을 2개 생성한다고 가정한다.
- @Primay 어노태이션이 없다면 빈 의존성 주입 시, 어떤 빈을 주입할지 몰라 NoUniqueBeanDefinitionException 예외가 발생한다.
- 하지만 @Primary 어노태이션을 붙임으로서, 타입이 같을 때 @Primay가 설정된 빈을 우선적으로 주입하게 된다.
2. @Lazy 애너테이션
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(SpringApplication.class);
// 스프링 컨테이너가 모든 빈의 설정들을 읽어와 빈 생성 완료
PriceUnit priceUnit = ctx.getBean("lazyPriceUnit", PriceUnit.class);
// 의존성이 주입되는 시점, ctx에서 getBean을 요청 했을 때 비로서 lazyPriceUnit 객체가 생성
ctx.close();
}
@Bean
@Lazy
public PriceUnit lazyPriceUnit() {
return new PriceUnit(Locale.US);
}
- 말 그대로 지연생성, 스프링 컨테이너가 생성될 때 빈 객체를 생성하는 것이 아닌 의존성이 주입하는 시점(객체가 요구되는 시점)에 비로소 컨테이너가 객체를 생성한다.
용어 정리
1. 스프링 빈 : 스프링 컨테이너에서 관리되는 객체
2. 자바 빈 : 기본 생성자가 선언되어있고, Getter/Setter가 있으며 Serializable을 구현하고 있는 객체
3. DTO(Data Transfer Object) : 소프트웨어 사이에 데이터를 전달하는 객체(비즈니스 로직이 없어야 한다)
4. 값 객체(Value Object, VO) : 특정 데이터를 추상화하여 데이터를 표현하는 객체(좌표계 표현, 돈 표현 등)
'공부 > Spring Boot' 카테고리의 다른 글
[스프링 부트 공부 일지] 3. 스프링에서 REST API 개발하기 (3) (0) | 2022.12.17 |
---|---|
[스프링 부트 공부 일지] 3. 스프링에서 REST API 개발하기 (2) (0) | 2022.12.16 |
[스프링 부트 공부 일지] 3. 스프링에서 REST API 개발하기 (1) (0) | 2022.12.16 |
[스프링 부트 공부 일지] 2. 스프링 웹 MVC (0) | 2022.12.15 |
[스프링 부트 공부 일지] 0. 공부를 시작하며 (0) | 2022.12.13 |