스프링 빈을 등록하는 방법은 4가지가 있다
스프링 버전에 따라 다르긴한데 XML(1.x) → @Component(2.5) → @Bean(3.0) → 함수형(5.0)으로 등록할수 있다
여기서 가장 중요한 구분기준은 내가 수정할수있는 소스코드를 가진 클래스인가를 확인해야한다
내 클래스라면 @Component를 사용하고 외부 라이브러리라면 @Bean을 쓰는 게 원칙이다
4가지 방법 한눈에 보기
| 방법 | 클래스 구분/ 타입 | 실무사용여부 | 장점 | 단점 |
| @Component 계열 | 내가 작성한 클래스/ 타입 안전 |
매우 많이사용함 | 코드가 간결함 역할이 명확함 레포지토리 예외 변환 부가기능 있음 |
외부 라이브러리 클래스에 못씀 조건부 등록 표현이 어려움 |
| @Bean | 모든 클래스/타입 안전 외부라이브러리 사용 |
많이 사용함 | 외부라이브러리 등록가능 복잡한 초기화 로직 자유롭게 작성가능 타입 안정성 보장 |
@Component 보다 코드량이 많음 반드시 @Configuration 안에 정의해야 싱글톤 보장 |
| XML설정 | 모든클래스/타입 불안전 외부라이브러리 사용 |
레거시 고칠때 사용 | 코드 변경없이도 설정 수정가능 비개발자도 설정파일 수정 가능 |
타입 안전성이 없음 오타는 런타임에 발견가능 IDE 지원약함 코드가 너무 김 |
| 함수형등록 | 모든클래스/타입 안전 외부라이브러리 사용 |
거의 사용안함 | 빠른 시작시간 람다로 타입 안전성 보장 리플렉션없음 |
코드가 너무 길고 불편함 AOP 통합이 복잡함 일반 프로젝트에서 사용하기 과하다 |
리플렉션 : 런타임(프로그램 실행 중)에 클래스, 메서드, 필드 등 객체의 메타데이터를 분석하고, 동적으로 조작(생성, 호출)할 수 있는 자바 API 및 프로그래밍 기법
자세히 알아보기
@Component 스캔 동작원리
@Service
public class UserService {
private final UserRepository repo;
public UserService(UserRepository repo) {
this.repo = repo;
}
}
@SpringBootApplication 안에 @ComponentScan이 포함되있어 메인클래스가 있는 패키지 아래에 있는 클래스를 자동으로 스캔한다 따라서 @Component,@Service,@Repository,@Controller어노테이션이 붙은 클래스를 스캔해서 Bean으로 등록한다
@Service,@Repository,@Controller는 @Component안에 속해 있으며 @Repository는 데이터 접근 예외상황을 스프링이 일관되게 정의한 DataAccessException으로 자동변환이 가능하다
@Service -> 비즈니스 로직 계층
@Repository-> 데이터 접근 계층
@Controller -> 웹 MVC 컨트롤러, 디스패쳐 서블릿이 요청을 위임함
NoSuchBeanDefinitionException
클래스가 스캔 범위 밖에 있을때 발생 따라서 해당 클래스를 사용하고 싶다면 스캔범위를 지정해줘야함
@SpringBootApplication(scanBasePackages = ...)
@Bean - 외부라이브러리와 CGLIB 프록시
CGLIB(Code Generation Library) 프록시 : 인터페이스 없이 구체 클래스를 상속받아 런타임에 바이트코드를 조작하여 동적으로 프록시 객체를 생성하는 기술
@Configuration 클래스 안에서 @Bean 어노테이션 메서드를 정의하면 등록이 가능하다 소스 코드를 수정할수 없는 외부 클래스에 사용할 수 있다
핵심은 CGLIB 프록시 사용이다 따라서 @Bean 메서드를 직접 호출해도 항상 같은 싱글톤의 인스턴스가 반환된다
여기서 주의할점은 @Configuration아니라 @Component를 사용하면 매번 새 인스턴스가 생기기때문에 주의해야한다
@Configuration // CGLIB 프록시 O
public class AppConfig {
@Bean
public A beanA() {
return new A(beanB()); // ①
}
@Bean
public B beanB() {
return new B();
}
@Bean
public C beanC() {
return new C(beanB()); // ②
}
}
결과
beanA() 호출됨
beanB() 첫 번째 호출 ID: #001
beanC() 호출됨
beanB() 두 번째 호출 ID: #001
매번같은 싱글톤 보장됨
@Component(lite mode) // CGLIB 프록시 X
public class AppConfig {
@Bean
public A beanA() {
return new A(beanB()); // ①
}
@Bean
public B beanB() {
return new B();
}
@Bean
public C beanC() {
return new C(beanB()); // ②
}
}
결과
beanA() 호출됨
beanB() 첫 번째 호출 ID: #001
beanC() 호출됨
beanB() 두 번째 호출 ID: #002
싱글톤 보장 안됨 -> 매번 새 인스턴스 생김
실무 선택 기준
대부분 Spring Boot 프로젝트는 @Component 계열과 @Bean 두가지 만으로 충분하다
XML은 레거시 프로젝트 유지보수에만 사용하고 함수형 등록은 서버리스·네이티브 이미지 환경이 아니면 사용하기 과하다
자주발생하는 문제 모음
@Configuration Lite Mode
싱글톤이 깨지는 경우
상황 : 설정 클래스에 @Configuration 대신 @Component를 사용했을때, @Bean 메서드 간 호출에서 매번 새 인스턴스가 생성된다
원인: @Component를 사용하면 CGLIB 프록시가 적용되지 않아(lite mode), @Bean 메서드가 일반 메서드처럼 호출된다
해결: Bean 간 의존 관계가 있는 설정 클래스는 반드시 @Configuration을 사용한다
BeanDefinitionOverrideException
Bean 이름 충돌
상황: 동일한 이름의 Bean이 두 곳에서 등록될 때 Spring Boot 2.1+에서 예외가 발생한다.
원인: 같은 클래스명을 가진 컴포넌트가 여러 패키지에 존재하거나, @Component와 @Bean으로 이중 등록됐다.
해결: @Bean('primaryDataSource')처럼 Bean 이름을 명시적으로 지정하거나, 중복 등록 원인을 찾아 제거한다.
'🐢 꼬부기 LV.1 | 개념•기초 > 💧물대포(핵심개념)' 카테고리의 다른 글
| Spring IoC 컨테이너란? (0) | 2026.04.06 |
|---|---|
| HTTP 메서드의 종류와 특징 (0) | 2026.03.26 |
| 리액트 설치후 실행에러 해결하기 (0) | 2026.03.23 |
| FileNotFoundError,NameError,PermissionError 해결하기 (0) | 2026.03.22 |
| 파이썬 데이터 분석 토이프로젝트 - 전기차 충전소 지역별 검색하기 (0) | 2026.03.21 |