Spring Boot로 서버를 만들며 시간에 쫓겨 프레임워크가 제시하는대로 구현은 했지만 세부적인 내용에 대한 이해가 부족하다고 느껴 기초부터 다시 정리하고 있다.
시작하기 전 Bean이 등록되고 준비되는 순서는 아래와 같다.
- @ComponentScan으로 클래스 경로에서 빈 정의 검색
- @Component, @Service, @Repository, @Controller - @Configuration 클래스와 @Bean 처리
- 프록시를 생성하고, 의존성을 관리 - 빈 생성(@Component 빈 먼저, @Bean 빈 나중에 생성 가능)
- 의존성 주입(@Autowired, 생성자, 필드, 메서드 주입)
- 빈 초기화(@PostConstruct, 커스텀 초기화 메서드)
- 애플리케이션 컨텍스트 준비
@Component
@Component는 Spring의 Bean으로 관리되는 클래스임을 나타내는 어노테이션이다. 이 어노테이션을 사용한 클래스는 Spring IoC(Inversion of Control) 컨테이너에 의해 자동으로 관리되며, 다른 컴포넌트에서 주입받아 사용할 수 있다.
- Spring은 @Component로 정의된 클래스를 자동으로 스캔하여 빈으로 등록
- @Component는 기본적인 빈 등록을 위한 어노테이션
사용 예시
@Component
public class MyService {
public void doSomething() {
System.out.println("Doing something");
}
}
Bean 등록
- Spring이 @Component가 붙은 클래스를 스캔하여 빈으로 등록한다. 일반적으로 @Component는 다른 @Service, @Repository, @Controller와 같은 세부 어노테이션의 기반이 된다. 즉, @Component는 그 자체로도 빈으로 등록되지만, 세부적인 역할을 명시하기 위해 @Service, @Repository, @Controller 등을 사용할 수 있다.
@Configuration
@Configuration은 Spring의 설정 클래스를 나타내는 어노테이션이다. 주로 Java-based Spring 설정을 작성할 때 사용된다. @Configuration이 붙은 클래스는 빈 정의를 포함하고 있으며, @Bean 어노테이션을 사용하여 빈을 정의할 수 있다.
- @Configuration은 @Component를 상속하여 빈으로 등록되지만, 이 클래스는 빈 설정을 위한 클래스라는 것을 나타낸다.
- @Configuration 클래스 내에서 @Bean 어노테이션을 사용하여 빈을 명시적으로 등록할 수 있다.
- @Configuration은 싱글턴 빈을 여러 번 생성하지 않도록 보장한다. @Configuration 클래스는 CGLIB(Code Generator Library) 프록시를 통해 동일한 객체가 여러 번 생성되지 않도록 주의해야 한다.
사용 예시
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyService();
}
}
Bean 등록
- @Configuration 클래스에서 @Bean 어노테이션을 사용하여 직접 빈을 등록할 수 있다.
- @Configuration은 보통 설정 클래스로 사용되며, 이 클래스는 애플리케이션 컨텍스트가 초기화될 때 설정 관련 빈들을 등록하는 역할을 한다.
위 내용 중 싱글턴 Bean(빈) 생성에 대해 좀 더 자세하게 알아보자.
만약 스프링이 설정 클래스를 평범한 클래스처럼 처리해서 myService() 메서드를 여러 번 호출한다면, MyService 객체가 여러 개 생성되게 된다. 이렇게 되면 스프링의 핵심 원칙 중 하나인 빈은 기본적으로 싱글턴이라는 원칙이 깨진다. 앞서 언급한 것처럼 @Configuration은 이 문제를 해결하기 위해 CGLIB(Code Generator Library)라는 프록시 기술을 사용한다.
스프링은 @Configuration 클래스를 일반적인 클래스로 사용하지 않고, 프록시 객체를 생성해서 대신 사용한다. 여기서 프록시란 진짜 클래스처럼 행동하지만, 내부적으로는 스프링이 제어할 수 있는 가짜 객체를 의미한다. 프록시 객체는 @Bean 메서드가 호출될 때, 이미 생성된 빈이 있는지 확인하고, 이미 생성된 빈이 있으면 그걸 반환하여 새로 생성하지 않는다. 그러므로 아래와 같은 상황에서도 문제를 발생시키지 않는다.
- 예시
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyService();
}
@Bean
public AnotherService anotherService() {
// MyService는 이미 생성된 싱글턴 빈을 사용
return new AnotherService(myService());
}
}
Bean(빈) 등록의 의미
Spring에서 "Bean"이란, Spring IoC(Inversion of Control) 컨테이너에 의해 관리되는 객체를 의미한다. Bean은 Spring의 핵심 요소로, 의존성 주입(DI)을 통해 애플리케이션의 구성 요소들이 서로 의존관계를 맺고, Spring 컨테이너가 이 객체들의 생명주기(lifecycle)를 관리한다.
Bean은 객체일 뿐만 아니라 Spring IoC 컨테이너가 이 객체를 관리하여, 애플리케이션 전체에서 재사용 가능하고, 애플리케이션의 설정을 추상화하는 중요한 역할을 한다.
Bean 등록
- Bean 등록은 Spring IoC 컨테이너에 객체를 등록하는 과정이다. 이 과정을 통해 Spring은 애플리케이션이 실행되는 동안 객체의 생명주기를 관리한다. 빈 등록은 주로 다음과 같은 방식으로 이루어진다.
- 자동 컴포넌트 스캔(@Component, @Service, @Repository, @Controller 등)
- 클래스에 @Component와 같은 어노테이션을 사용하여 해당 클래스가 Spring IoC 컨테이너에 의해 관리되는 빈으로 자동 등록되도록 한다.
- 명시적 Bean 등록(@Bean 어노테이션 사용)
- @Configuration 클래스를 사용하고, 그 안에 @Bean 어노테이션을 사용하여 특정 객체를 빈으로 명시적으로 등록한다.
- XML 기반 설정(전통적인 방법)
- XML 파일에서 <bean> 태그를 사용하여 빈을 정의한다. (Spring 3 이후로는 Java-based 설정을 더 많이 사용)
- 자동 컴포넌트 스캔(@Component, @Service, @Repository, @Controller 등)
정리
- @Component: 빈으로 등록할 클래스를 정의한다. 해당 클래스는 Spring IoC 컨테이너에 자동으로 등록되며, 다른 클래스에서 의존성 주입을 통해 사용할 수 있다.
- @Configuration: Spring의 설정 클래스를 정의한다. 주로 @Bean 어노테이션을 사용하여 명시적으로 빈을 등록하며, @Configuration 클래스는 싱글턴으로 관리된다.
- Bean(빈) 등록: Spring IoC 컨테이너에 객체를 등록하는 과정으로, 애플리케이션에서 객체들이 서로 의존성을 주고받으며 동작할 수 있게 된다.
추가적으로 @Configuration은 @Component보다 더 높은 우선순위를 가지고 있다. @Configuration 클래스 내부에서 생성된 @Bean 메서드들은 먼저 처리된 후, @Component로 등록된 빈들이 처리되고 의존성 주입이 완료된다.
관련 포스팅