Spring Bean

이완희·2023년 8월 20일

개요

Spring으로 개발을 하면서 다양한 Annotation을 만났지만 “이걸 왜 쓰지?”라는 의문 없이 무작정 써왔다.

이제껏 모를 수 있어도 앞으론 모르지 말자. 기록하고, 익히고, 체득하자.

Bean

아래 어노테이션을 이해하기 전에 Bean의 개념에 대해 짚고 넘어가자.

쉽게 말하자면 스프링 IoC 컨테이너(= 스프링 컨테이너)가 관리하는 자바 객체(POJO)인데 생명주기가 관리되는 객체이다. 스프링 프레임워크의 특징 중 하나는 제어의 역전입니다. 근데 무엇을 제어하는가? Bean입니다. 아래 어노테이션들은 빈을 추가하여 스프링 컨테이너가 인식하게 해주는 방법들입니다.

  • Component VS Bean

    Component는 싱글톤 빈을 생성한다. 클래스 단위로 생성되며 Service, Repository, Controller가 여기에 포함된다. 개발자가 직접 컨트롤이 가능한 Class에 선언한다.

    Bean은 @Configuration이 들어간 클래스 내에 메소드에 선언한다. 개발자가 컨트롤이 불가능한 외부 라이브러리를 Bean객체로 선언하고 싶을때 사용한다.

  • Repository, Service, Controller(RestController)

    세가지 어노테이션의 차이는 없다고 봐도 됩니다. 실제로 코드를 봤을때도 전부 선언된 어노테이션이 동일합니다.

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Component

    사실상 @Component를 사용하셔도 무방합니다만, 로직의 분리를 위해서 나눠서 써줍시다.

    참고로 @RestController은 @Controller + @ResponseBody입니다. Controller은 view뿐만 아니라 Data를 반환할 수도 있습니다. REST API를 개발할 때 JSON 형태의 객체 데이터를 반환하기 위해 ResponseEntity로 객체를 반환합니다. HttpStatus등의 객체를 담기 위해선 @ResponseBody가 필요하므로 REST API를 개발할 땐 @RestController을 사용하면 됩니다.

의존 객체 자동 주입

Autowired에서 필요한 과정을 살펴보자.

@Component로 객체를 스프링 Bean에 등록한다 → @Autorwired를 통해 등록된 빈에서 필요한 의존 관계를 설정한다.(타입을 우선으로 Bean 탐색) 하지만 Bean의 이름이 중복되면 오류가 발생한다. 이런 경우엔 @Qualifier나 @Primary를 사용하여 해결할 수 있다.

@Autowired
@Qualifier("sse-topic")
private ChannelTopic channelTopic;

Bean에 이름을 등록하여(Alias)중복을 방지한다.

@Primary는 여러 타입의 Bean이 존재할 때, 특정 Bean을 우선적으로 주입받게 해준다.

@Resource와 @Inject는 Spring이 아닌 Java가 제공하는 애들이다. @Autowired와 달리 Type이 아닌 Name이 우선이며, 생성자에는 붙일 수 없다.

근데 어차피 DI는 @Autowired가 권장되지 않아 생성자 주입 방법만 사용하는데 얘들이 이제 필요할까?

스코프

@Scope를 통해 Bean의 스코프를 지정할 수 있습니다. 스프링은 컨테이너에 선언한 Bean마다 하나의 인스턴스를 생성하고 이렇게 만들어진 인스턴스는 전체 컨테이너 스코프에 공유됩니다. Bean의 스코프는 기본적으로 singleton입니다.

singletonIoC 컨테이너당 빈 인스턴스 하나를 생성
prototype요청할 때마다 빈 인스턴스를 새로 생성
requestHTTP 요청당 하나의 빈 인스턴스 생성
sessionHTTP 세션당 빈 인스턴스 하나를 생성
globalSession전역 HTTP 세션당 빈 인스턴스 하나를 생성

초기화/폐기 커스터마이징

Bean의 생성주기는 생성 → 초기화 → 사용 → 소멸이다. 간략하게 짚고 넘어가자.

@PostConstruct, @PreDestroy

@Component에 대해서만 동작 한다. 말 그대로 생성 이후에, 폐기 이전에 실행된다.

@Lazy

스프링은 POJO를 즉시 호출(Eager Loading)하는데 비해 @Lazy는 여유롭게 호출(Lazy Loading)한다. 애플리케이션이 요구하거나 다른 POJO가 참조하기 전까지 초기화 되지 않는다. 한번에 모든 Bean을 호출하는 행위가 무거워서 부담이 될 수 있다. 이를 이용하면 초기 실행시 더욱 성능 개선을 기대할 수 있다. 다만 Bean을 호출하기 전까지는 어떤 오류가 있는지 알수도 없다.

profile
인생을 재밌게, 자유롭게

0개의 댓글