당니의 개발자 스토리
@Component vs @Bean 본문
묵시적 DI와 명시적 DI는 어떻게 다를까
Spring에서 DI를 배우다 보면 자연스럽게 두 가지 방식이 등장한다.
@Component
@Bean
처음 보면 둘 다 Bean 등록인데 뭐가 다른지 헷갈린다.
이 글에서는 이 두 개를 정확하게 구분한다.
먼저 결론부터 보면 이렇게 정리된다.
@Component → 자동 등록 (묵시적 DI)
@Bean → 직접 등록 (명시적 DI)
이제 하나씩 이해해보자.
먼저 @Component부터 보자.
@Component
public class SWasher implements Washer {}
이렇게 작성하면 Spring은 이 클래스를 자동으로 Bean으로 등록한다.
이게 가능한 이유는 ComponentScan 때문이다.
Spring은 실행될 때 특정 패키지를 스캔하면서 @Component가 붙은 클래스를 전부 찾아낸다.
그리고 내부에서 이런 흐름이 일어난다.
1. 클래스 발견 (@Component)
2. 객체 생성
3. Container에 Bean으로 등록
그래서 개발자는 new를 한 번도 쓰지 않는다.
이걸 묵시적 DI라고 한다.
"이걸 Bean으로 만들어주세요"
라는 코드를 직접 쓰지 않았기 때문이다.
그냥 Spring이 알아서 처리한다.
그래서 실무에서는 대부분 이 방식을 기본으로 사용한다.
특히 이런 경우에 사용한다.
Controller
Service
Repository
비즈니스 로직 클래스
내가 만든 클래스들은 대부분 @Component 계열로 등록한다.
그래서 실제로 각각 이렇게 쓴다.
@Controller
@Service
@Repository
이것들도 전부 @Component의 일종이다.
이제 @Bean을 보자.
@Configuration
public class AppConfig {
@Bean
public SWasher sWasher() {
return new SWasher();
}
}
이건 완전히 다른 방식이다.
이번에는 Spring이 자동으로 찾는 게 아니라,
개발자가 직접 Bean을 등록한다.
1. @Configuration 클래스 로딩
2. @Bean 메서드 실행
3. 반환 객체를 Bean으로 등록
즉, 흐름은 이렇게 된다.
"이 객체를 Bean으로 등록해줘"
라고 명시적으로 말해주는 구조다.
그래서 이걸 명시적 DI라고 한다.
여기서 중요한 차이가 하나 있다.
@Component는 클래스 기반
@Bean은 메서드 기반
@Component는 클래스 위에 붙인다.
@Component
class A {}
@Bean은 메서드 위에 붙인다.
@Bean
public A a() {
return new A();
}
그럼 둘 중에 언제 뭘 써야 할까?
먼저 @Component를 사용하는 경우다.
내가 만든 클래스
구조가 단순한 객체
비즈니스 로직 클래스
이런 경우에는 무조건 @Component 계열을 쓰는 게 편하다.
코드도 짧고, 자동 등록되기 때문이다.
반대로 @Bean을 사용하는 경우는 명확하다.
외부 라이브러리 객체
생성 과정이 복잡한 객체
설정이 필요한 객체
이런 경우다.
예를 들어 ObjectMapper를 생각해보자.
ObjectMapper mapper = new ObjectMapper();
이 클래스는 내가 만든 게 아니다.
그래서 여기에 @Component를 붙일 수 없다.
이럴 때는 이렇게 등록한다.
@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper();
}
이게 @Bean이 필요한 이유다.
또 하나 중요한 차이는 의존성 주입 방식이다.
@Bean에서는 파라미터로 자동 주입이 가능하다.
@Bean
public WasherUser washerUser(SWasher washer) {
WasherUser user = new WasherUser();
user.setWasher(washer);
return user;
}
여기서 washer는 Spring이 자동으로 넣어준다.
즉 @Autowired를 따로 안 써도 된다.
이걸 보면 처음에는 이렇게 생각하기 쉽다.
"어차피 set으로 넣는 거면 강결합 아닌가?"
하지만 누가 객체를 new로 생성했느냐 가 중요하다.
new로 생성한 것이 아니면 강한 결합으로 볼 수 없다.
이 코드는 이렇게 동작한다.
Spring이 SWasher 생성
→ washerUser 메서드 호출
→ washer를 파라미터로 전달
→ WasherUser에 주입
개발자가 new SWasher()를 한 적이 없다.
즉 객체 생성 책임은 여전히 Spring에 있다.
그래서 결합도가 낮다.
여기까지 정리하면 이렇게 된다.
묵시적 DI (@Component)
자동 등록
코드 간결
구조 파악 어려울 수 있음
명시적 DI (@Bean)
직접 등록
구조 명확
코드 길어질 수 있음
그래서 실무에서는 이렇게 사용한다.
기본은 @Component
필요할 때만 @Bean
특히 외부 라이브러리는 거의 무조건 @Bean이다.
'Java, Spring' 카테고리의 다른 글
| Spring Bean 생명주기 (0) | 2026.05.06 |
|---|---|
| @Autowired와 @Qualifier (0) | 2026.05.06 |
| DI는 왜 필요할까? 객체 생성 책임과 Spring Container (0) | 2026.05.06 |
| Maven, 빌드 자동화 도구에 대해서 (0) | 2026.05.06 |
| JUnit과 Assertion으로 테스트 코드 작성하기 (0) | 2026.05.06 |