스프링을 공부하다 보면 @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 |