Back_End/Spring

스프링 @Bean, @Configuration, @Component 이란?

10Biliion 2025. 3. 31. 11:51
반응형

1. 스프링 빈(Bean)이란?

스프링 프레임워크에서 빈(Bean)스프링 컨테이너가 관리하는 객체를 의미합니다. 일반적인 Java 객체와 동일하지만, 스프링의 IoC(Inversion of Control) 컨테이너에 의해 생성 및 관리됩니다.

🔹 스프링 빈의 특징

  1. 스프링 컨테이너가 직접 객체를 생성 및 관리
  2. 싱글톤(Singleton)으로 관리 (기본 설정 시)
  3. DI(Dependency Injection, 의존성 주입) 지원
  4. 필요할 때 스프링 컨테이너에서 빈을 가져와 사용 가능

2. @Bean 어노테이션

@Bean개발자가 직접 제어할 수 있는 방법으로 스프링 빈을 등록할 때 사용됩니다. 주로 @Configuration과 함께 사용되며, 메서드에 붙여서 해당 메서드가 반환하는 객체를 스프링 컨테이너가 관리하는 빈으로 등록합니다.

✅ @Bean 사용 방법

@Configuration
public class AppConfig {
    @Bean
    public MyService myService() {
        return new MyService();
    }
}

위 코드에서 myService() 메서드가 반환하는 객체는 스프링 컨테이너에 의해 빈으로 등록됩니다.

🔹 @Bean의 특징

  • 메서드 이름이 빈의 이름이 됨 (예: myService)
  • 개발자가 직접 객체 생성 로직을 제어 가능
  • 외부 라이브러리 등의 클래스를 빈으로 등록할 때 유용
  • 싱글톤을 보장하려면 반드시 @Configuration과 함께 사용해야 함

3. @Configuration 어노테이션

@Configuration해당 클래스가 하나 이상의 @Bean을 정의하고 있음을 나타내는 설정 클래스를 의미합니다.

✅ @Configuration 사용 방법

@Configuration
public class AppConfig {
    @Bean
    public MyService myService() {
        return new MyService();
    }
}

🔹 @Configuration의 특징

  1. @Bean을 여러 개 포함할 수 있는 설정 클래스
  2. 싱글톤을 보장 (@Component 와의 차이점)
  3. 다른 빈과의 의존 관계 설정 가능

✅ @Configuration 싱글톤 보장 예제

@Configuration
public class AppConfig {
    @Bean
    public AService aService() {
        return new AService(bService());
    }

    @Bean
    public BService bService() {
        return new BService();
    }
}

위 코드에서 aService()에서 bService()를 호출하지만, 스프링 컨테이너가 관리하는 동일한 bService 인스턴스가 사용됩니다.

@Configuration을 사용하지 않으면 싱글톤이 깨질 수 있음

public class AppConfig {
    @Bean
    public AService aService() {
        return new AService(bService());
    }

    @Bean
    public BService bService() {
        return new BService();
    }
}

위처럼 @Configuration이 없으면 bService()가 호출될 때마다 새로운 객체가 생성됩니다. 따라서 @Bean을 사용할 때는 반드시 @Configuration을 함께 사용하여 싱글톤을 보장해야 합니다.


4. @Component 어노테이션

@Component개발자가 직접 클래스를 스프링 빈으로 등록할 때 사용합니다. @ComponentScan을 사용하면 해당 패키지 내의 @Component가 붙은 클래스들이 자동으로 빈으로 등록됩니다.

✅ @Component 사용 방법

@Component
public class MyService {
    public void doSomething() {
        System.out.println("MyService 실행");
    }
}

🔹 @Component의 특징

  • 클래스 수준에서 사용됨 (메서드 X)
  • 자동으로 빈 등록 가능 (@ComponentScan 필요)
  • @Service, @Repository, @Controller 등과 같은 스테레오타입 어노테이션과 함께 사용

✅ @ComponentScan과 함께 사용하기

@Configuration
@ComponentScan(basePackages = "com.example.service")
public class AppConfig {}

위 코드처럼 @ComponentScan을 사용하면 com.example.service 패키지 내의 @Component가 붙은 모든 클래스가 자동으로 빈으로 등록됩니다.


5. @Bean vs @Component 비교


구분 @Bean @Component
적용 대상 메서드 클래스
등록 방식 개발자가 직접 등록 자동 스캔 (@ComponentScan 필요)
외부 라이브러리 O X
싱글톤 보장 O (@Configuration 필요) O
✅ 언제 사용해야 할까?
  • 일반적으로는 @Component를 사용
  • 개발자가 직접 제어가 불가능한 라이브러리를 활용할 때@Bean + @Configuration
  • 애플리케이션 전 범위적으로 사용되는 클래스를 등록할 때@Bean + @Configuration
  • 다형성을 활용하여 여러 구현체를 등록해야 할 때@Bean + @Configuration

 

 

[ @Configuration 내부에서 @Bean을 사용해야 하는 이유  ]

  • @Configuration 내부에서 @Bean을 사용하면 Spring이 CGLIB 프록시를 활용하여 싱글톤을 보장함.
  • @Component + @Bean을 사용할 경우 싱글톤이 깨질 가능성이 있음.
  • @Bean 메서드를 직접 호출하지 말고, 생성자 주입을 통해 의존성을 해결하는 것이 올바른 방법.

 

1. CGLIB 프록시를 통한 싱글톤 보장

  • @Configuration 클래스는 내부적으로 CGLIB을 이용한 프록시 객체로 등록됩니다.
  • 이 프록시 객체는 @Bean 메서드가 여러 번 호출되더라도 동일한 인스턴스를 반환하도록 보장합니다.
  • 즉, @Configuration 내부에서 @Bean을 선언하면 Spring 컨테이너에서 관리하는 싱글톤 객체로 등록됩니다.

2. 직접 @Component + @Bean 사용 시 문제

@Component
public class AppConfig {
    @Bean
    public MyService myService() {
        return new MyService();
    }
}

 

  • 위와 같이 @Component 안에서 @Bean을 선언하면 CGLIB 프록시가 적용되지 않음.
  • myService() 메서드가 여러 번 호출될 때마다 새로운 객체가 생성될 수 있음.

3. 잘못된 사용 예시

@Configuration
public class AppConfig {
    @Bean
    public MyService myService() {
        return new MyService();
    }

    @Bean
    public AnotherService anotherService() {
        return new AnotherService(myService()); // myService()가 직접 호출됨
    }
}
  • myService()를 직접 호출하면 CGLIB 프록시를 거치지 않기 때문에 새로운 객체가 생성됨.
  • @Configuration 내부에서 @Bean을 호출하면 프록시를 통해 싱글톤이 유지됨.

4. 해결 방법

@Configuration
public class AppConfig {
    @Bean
    public MyService myService() {
        return new MyService();
    }

    @Bean
    public AnotherService anotherService(MyService myService) { // 생성자 주입
        return new AnotherService(myService);
    }
}
  • @Bean 메서드끼리 의존성을 주입할 때는 직접 호출하지 말고 생성자 주입을 활용해야 함
  • @Bean개발자가 직접 제어할 수 있는 빈 등록 방법
  • @Configuration설정 클래스이며 @Bean 메서드를 포함
  • @Component자동으로 빈 등록이 필요한 경우 사용
반응형