Spring - Component vs Bean vs Configuration

스프링을 공부하다 보면 @Component, @Bean, @Configuration 세 가지 어노테이션을 마주하게 된다.

전부 스프링 빈(Bean)을 등록할 때 쓰는 것 같은데, 대체 무슨 차이가 있고 언제 뭘 써야 할지 헷갈릴 때가 많다.

 

이번 기회에 개념을 명확히 정리하고, 실제 실무에서 어떻게 쓰이는지

그리고 멀티 DB 설정 예시까지 곁들여서 깔끔하게 정리해 보려고 한다.

 

1. @Bean vs @Component 

구분 @Bean @Component
선언 위치 메소드 레벨 클래스 레벨
등록 방식 개발자가 코드로 직접 수동 등록 스프링이 런타임에 자동으로 스캔해서 등록
주요 대상 개발자가 수정할 수 없는 외부 라이브러리 객체 개발자가 직접 만든 내부 클래스

 

💡 좀 더 쉽게 이해하기

내가 직접 만든 클래스(Controller, Service 등)는 클래스 위에 @Component만 툭 붙여두면 스프링이 알아서 가져간다.

 

하지만 내가 만든 게 아니라 외부 라이브러리(예: 인코더, DB 커넥션 풀 등)에서 가져온 객체클래스 내부에

어노테이션을 붙일 수가 없다.

 

이때 개발자가 직접 메소드를 만들어 객체를 생성하고, 그 위에 @Bean을 붙여 수동으로 스프링에게 쥐여주는 것이다.

 

2. @Configuration - "여기 수동 Bean 맛집입니다"

그렇다면 @Configuration은 왜 필요할까?

 

이 어노테이션은 쉽게 말해 "이 클래스는 수동으로 등록할 @Bean들이 모여있는 설정 파일입니다"라고

스프링에게 알려주는 역할을 한다.

 

하나의 클래스 안에서 수동으로 여러 개의 빈을 한 번에 등록하고 관리할 때 사용한다.

@Configuration // 한 개의 클래스에서 여러 개의 bean을 등록할 때 사용하는 어노테이션
class AppConfig {

    @Bean("base64Encode") // Encoder라는 동일한 자료형의 객체이니까 Bean 어노테이션에 이름을 붙여준다.
    public Encoder encoder(Base64Encoder base64Encoder) {
        return new Encoder(base64Encoder);
    }

    @Bean("urlEncode") // 이름이 겹치지 않게 명시적으로 지정!
    public Encoder encoder(UrlEncoder urlEncoder) {
        return new Encoder(urlEncoder);
    }
    // 이처럼 스프링 컨테이너 안에서 다양한 Bean들을 담아서 한 번에 관리할 수 있다.
}​

 

[ 실전 활용 ] - 멀티 DB 설정을 위한 DatasourceConfig 작성하기

이론은 알겠는데, "실무에서 @Configuration이랑 @Bean을 이렇게 수동으로 다 쪼개서 등록할 일이 진짜 있나?" 싶을 수 있다.

 

가장 대표적인 실무 케이스가 바로 "하나의 프로젝트에 여러 개의 DB를 붙여야 하는 멀티 DB 환경"이다.

어설프게 설정하면 '이 쿼리가 대체 어느 DB로 날아가는 거지?' 하고 멘붕이 오기 딱 좋은 영역이기도 하다.

(실제로 내가 현재 진행중인 프로젝트에서는 무려 4개의 DB가 붙어있는 상황이다.)

만약 DB가 4개라면 아래 객체들이 세트로 생성되어야 한다.

  • HikariConfig (커넥션 풀 설정 및 관리자)
  • DataSource (실제 DB 연결 커넥션)
  • SqlSessionFactory (MyBatis 세션 팩토리)
  • SqlSessionTemplate (실제 SQL 실행 진입점)
  • TransactionManager (트랜잭션 관리)

스프링이 자동으로 다 잡아줄 수 없기 때문에, 이때 @Configuration 클래스 안에서 @Bean으로 수동 등록해 줘야 한다.

 

@Configuration
public class DatasourceConfig {

    // 1. main DB용 세팅
    @Primary // "아무 명시 없으면 기본값으로 얘를 써라!"
    @Bean
    public DataSource maindbDataSource() { ... }

    @Primary
    @Bean
    public SqlSessionTemplate maindbSqlSessionTemplate() { ... }

    // 2.sub DB용 세팅 (서브 DB)
    @Bean
    public DataSource subdb1DataSource() { ... }

    @Bean
    public SqlSessionTemplate subdb1SqlSessionTemplate() { ... }
    
    // ... 이런 식으로 4세트를 전부 @Bean으로 수동 등록해 준다!
}

 

 

⚠️ 멀티 DB 설정 시 주의할 점! (@Primary와 @Qualifier)

똑같은 타입의 빈(DataSource 등)이 4개나 스프링 컨테이너에 올라가면,

스프링은 주입할 때 어떤 걸 가져와야 할지 몰라 에러를 뿜는다. 이때 두 어노테이션의 조합이 필요하다.

 

  • @Primary : "따로 말 안 하면 이걸 기본값으로 써라." 우리 프로젝트에서는 main 계열 빈들에 다 발라둔다. (참고로 타입별로 동작하기 때문에 DataSource, SqlSessionTemplate 등 각 타입의 main 빈에 다 붙여야 한다.)

  • @Qualifier : "내가 콕 집어서 고르기." 서브 DB(saora, hrora 등)를 사용할 때는 주입받을 때 반드시 @Qualifier("saoraSqlSessionTemplate") 처럼 명시해 줘야 한다.

만약 귀찮다고 @Qualifier를 빼먹으면 어떻게 될까?

@Primary로 설정된 mainDB 세션이 주입되어, subDB로 가야 할 쿼리가 mainDB로 날아가 데이터가 꼬이거나

에러를 뱉게될 것이다.

💡 한 줄 요약: @Qualifier는 단순히 주입 편의를 위한 게 아니라, 내 Mapper가 연결될 '진짜 DB 세션'을 정확히 배달해 주는 안전장치다.

'Spring' 카테고리의 다른 글

ContextConfiguration이란?  (0) 2022.01.19
Spring - Junit Test  (0) 2022.01.17
Spring - Bean과 ioc에 대해서 (예제 코드)  (0) 2022.01.11
Spring - DI (의존성 주입) 이란 무엇인가?  (0) 2022.01.11
Spring - 왜 Spring을 쓰는가?  (0) 2022.01.11