스프링 빈과 관련하여..

도비·2023년 10월 30일
0

Spring Boot

목록 보기
5/13
post-thumbnail

어느 날 면접을 봤는데... "스프링 빈에 대해서 개발 분야에 무지한 사람에게 설명해준다고 할 때 어떻게 할 것이냐?" 라는 질문을 받았다.
사실, 개발을 하면서 재사용하고 싶은 객체가 있으면 아무런 의식 없이 @Bean어노테이션을 붙여 사용했던터라.. 이 질문을 듣고 대답하면서 충분한 대답을 하지 못한 것 같아 아쉬움이 남았다.

그래서 정말 처음 개발하는 사람에게, 혹은 아예 스프링을 모르는 사람에게 설명해준다고 생각하고 스프링 빈, 대체 무엇이고 어떻게 관리되는가? 를 적어보려고 한다.

아쉬움 뒤엔 성장이 있는 법이니까!

스프링 빈이 뭔데?

사실 개발자가 알고 있는 단어로 설명하자면 스프링 빈은 Spring IoC가 관리하는 자바 객체라고 설명할 수 있겠다.
하지만, 만약 Java를 모르고 개발도 처음이라면, Spring IoC가 무엇이고, 자바 객체는 무엇인데? 라는 생각을 할 수 있을 것이다.

자바 객체

차근 차근 설명해보자면, 우선, 자바는 객체지향 프로그래밍 기반의 언어이다. 객체지향 프로그래밍을 짧게 설명해보자면, 프로그램의 구성 요소를 객체로 나누는 것이다. 그래서 어떤 역할을 하고자 할 때, 우리는 객체를 생성해서 그 객체에 역할을 부여해준다.

Spring IoC

그러면 Spring IoC는 무엇인가?
제어의 역전이다. (응?)

위에 설명했듯이 자바 프로그램에서는 프로그래머가 직접 객체를 생성하고, 원하는 클래스 내에서 다른 객체를 생성해 사용했다. 이 경우 프로그래머가 객체의 생명주기를 관리하고 있다.

그런데 제어의 역전이 일어나면, 프로그래머가 아닌 다른 무언가가 관리를 위임하게 된다. 프로그래머의 제어 권한을 다른 주체에게 넘기는 것을 IoC(제어의 역전)라고 한다. Spring은 직접 자바 객체를 생성하고 관리하기 때문에, 이 관리 위임 주체는 Spring 이다.

스프링 빈은, 스프링에 의해 생성되고, 라이프 사이클을 수행하고, 의존성 주입이 일어나는 객체를 얘기한다.

스프링에서는 빈을 어떻게 인지하는가?

그렇다면, 스프링은 이러한 자바 객체가 있다는 것을 두 가지 방법으로 알 수 있다.

  • 약속되어 있는 어노테이션이 붙어있는 클래스로 자동으로 인지한다.
  • Bean Configuration File에 직접 Bean을 등록하면 스프링이 인지할 수 있게 된다.
  1. 어노테이션을 붙인 클래스를 인지한다
    아래에서 설명하는 어노테이션이 붙어있다면, 스프링이 자동으로 빈을 인지할 수 있게 된다.
  • @Component
    스프링이 관리하는 요소라는 의미를 주는 일반적인 어노테이션
  • @Bean

이 두가지 어노테이션이 붙어있으면 스프링 내부에서 자바 객체를 빈으로 등록하는데, 우리가 아는 @Service, @Controller, @Repository 도 구현문 안에 이런 식으로 @Component라는 어노테이션이 붙어있어서 빈으로 자동으로 등록이 된다.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {

	/**
	 * The value may indicate a suggestion for a logical component name,
	 * to be turned into a Spring bean in case of an autodetected component.
	 * @return the suggested component name, if any (or empty String otherwise)
	 */
	@AliasFor(annotation = Component.class)
	String value() default "";

}
  1. Bean Configuration File에 직접 Bean을 등록할 수 있다.
@Configuration
public class GlobalConfiguration {
    @Bean
    public Controller sampleController() {
        return new Controller;
    }
}

스프링에서는 빈을 어떻게 관리하는가?

스프링 빈(Bean)의 인스턴스화, 구성, 전체 생명 주기 및 관리는 스프링 컨테이너에서 관리한다. (스프링 컨테이너의 역할이 내부에 존재하는 빈의 생명주기를 관리하며, 생성된 빈에게 추가적인 기능을 제공하는 것이다.)

그렇다면 스프링 컨테이너가 어떻게 빈을 관리하는 것일까?
1. 가장 처음에는 Spring IoC 컨테이너가 만들어지는 과정이 일어난다.
2. 개발자가 등록한 Bean들을 어노테이션이나 설정 파일을 읽어 IoC 컨테이너 안에 Bean으로 등록시킨다.
3. 의존성을 주입하기 전의 준비 단계에서 객체의 생성이 일어난다.

이를 정리해보며 빈의 생명 주기를 한번 살펴보자.

스프링 빈 라이프 사이클

스프링 IoC 컨테이너 생성 -> 스프링 빈 생성 -> 의존관계 주입 -> 초기화 콜백 메소드 호출 -> 사용 -> 소멸 전 콜백 메소드 호출 -> 스프링 종료

스프링 의존관계 주입이 완료되면 스프링 빈에게 콜백 메소드를 통해 초기화 시점을 알려주며, 스프링 컨테이너가 종료되기 직전에도 소멸 콜백 메소드를 통해 소멸 시점을 알려준다.

그러면 여기서 궁금해지는게, 콜백은 대체 무엇일까? 라는 점이다.

콜백은 어떤 이벤트에 의해 호출되는 함수라고 간단하게 설명하고 넘어가겠다.

다시 한 번 자세히 살펴보자면,

스프링 빈은 객체를 생성하고 의존 관계 주입이 다 끝난 다음에야 필요한 데이터를 사용할 수 있는 준비가 완료된다. 따라서 초기화 작업은 의존관계 주입이 모두 완료되고 난 다음에 호출해야 한다. 개발자가 의존 관계 주입이 모두 완료된 시점을 어떻게 알 수 있을까?

스프링은 의존관계 주입이 완료되면 스프링 빈에게 콜백 메서드를 통해 초기화 시점을 알려주는 다양한 기능을 제공한다.

이런 콜백에도 여러가지 종류가 있다.

- 인터페이스 방식
Initializing Bean은 afterPropertiesSet() 메서드로 초기화를 지원한다.
DisposableBean은 destroy() 메서드로 소멸을 지원한다.
하지만 이 인터페이스는 스프링 전용 인터페이스이다.
따라서 해당 코드가 스프링 전용으로 스프링 없는 환경에서의 단위 테스트가 힘들다. 또한 초기화, 소멸 메서드의 이름을 변경할 수 없고, 외부 라이브러리에 적용할 수 없다. 최근에 거의 사용하지 않는 방식이다.

- 빈 등록 초기화, 소멸 메서드 지정 방식
빈 등록 설정 정보에 @Bean(initMethod="init", destroyMethod="close")처럼 초기화, 소멸 메서드를 지정한다. 이러한 방식은 메서드 이름을 자유롭게 줄 수 있다. 스프링 빈이 스프링 코드에 의존하지 않는다. 또한 코드가 아닌 설정 정보를 이용하기 때문에 코드를 고칠 수 없는 외부 라이브러리에도 적용할 수 있다.

- @PostContruct, @PreDestroy 어노테이션 방식
@PostConstruct, @PreDestroy 어노테이션을 사용하여 가장 편리하게 초기화, 종료를 실행할 수 있다.
최신 스프링에서 가장 권장하는 방식으로 어노테이션 하나만 붙이면 되므로 매우 편리하다. 스프링에 종속적이지 않고 자바 표준이다. 따라서 스프링이 아닌 다른 컨테이너에서도 잘 동작한다. 유일한 단점은 외부 라이브러리에 적용하지 못한다는 점이다. 이때는 @Bean의 지정 방식을 사용하자.


이런 콜백 함수까지 지원이 되는지는 이번에 공부해보면서 알았다.

아무튼 이 기회에 알아가는 스프링 빈과 라이프 사이클... 면접에서 말을 못한게 아쉽지만, 많이 알아갈 수 있어서 좋은 시간이었다!

다음엔 빈 질문 받으면 확실하게 답할 수 있겠다!🥲

profile
하루에 한 걸음씩

0개의 댓글