@Compoent 와 @Bean 은 뭔 차이지?

kms·2024년 1월 3일
1

예제에서 사용한 모든 코드는 Github Repository 에 있습니다.

스프링으로 개발하다 보면 필요한 객체들은 스프링 컨테이너에서 관리하는 빈으로 등록하여 사용할 경우가 생깁니다.

이때 @Congiguration 설정과 함께 원하는 의존관계를 만족하는 인스턴스를 반한하도록 하는 메서드를 만든 후 그 위해 @Bean 애노테이션을 선언하여 만듭니다. 혹은 필요한 클래스 위에 @Componet 를 선언하여 사용하기도 합니다.

주로 @Configuration 과 함께 @Bean 쓰이고, 왜 @Component 는 같이 안썻던걸까?
그리고 @Bean 과 @Component 는 어떤 차이가 있는 걸까?

@Configuration, @Bean

@Bean은 메소드 수준에서 사용할 수 있는 에너테이션입니다. 그리고 @Configuration 과 @Bean 이 같이 선언되었을 때 선언된 메서드는 스프링 컨테이너에 의해 관리될 빈을 만들게 됩니다.

이렇게 @Bean이 붙은 매서드에서 원하는 오브젝트 간 의존관계를 자바 코드를 이용하여 직접 만들 수 있습니다.


@Configuration
public class AppConfig {

     @Bean
     public FooService fooService() {
         return new FooService(fooRepository());
     }

     @Bean
     public FooRepository fooRepository() {
         return new JdbcFooRepository(RedisDataSource());
     }
 }

이때 @Configuration는 하나 이상의 @Bean 메소드를 선언하고 런타임 시 해당 Bean에 대한 Bean 정의 및 서비스 요청을 생성하기 위해 Spring 컨테이너에서 처리될 수 있도록 한다.

그렇다면 @Component 와 @Bean 은 같이 사용할 수 없는 걸까? 그건 아니다.
@Component 애노테이션이 붙은 클래스 내부에 @Bean 이 있어도 결국 @Component는 당연히 컴포넌트 스캔의 대상이 되기 때문에 해당 Config 파일을 찾을 수 있습니다.

@Component
class AppConfig{
	@Bean
    public MemberService memberService() {
        return new MemberServiceImpl();
    }
}
public class BeanTest {

    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

    @Test
    void findApplicationBeanTest() {
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);

            if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
                Object bean = ac.getBean(beanDefinitionName);
                System.out.println("objectName = " + beanDefinitionName + ", object = " + bean);
            }
        }
    }
}


appConfig 와 memberService 라는 이름으로 두 객체가 빈으로 등록된 것을 볼 수 있습니다.

그렇다면 왜 굳이 @Configuration 와 함께 @Bean 을 사용하는 걸까요?

관련해서 Spring 에서는 다음과 같이 언급하고 있는데요.

You can use @Bean-annotated methods with any Spring @Component. However, they are most often used with @Configuration beans.
...
@Configuration classes let inter-bean dependencies be defined by calling other @Bean methods in the same class.

@Configuration 클래스는 동일한 클래스 내의 다른 @Bean 메소드를 호출함으로써 빈 간의 의존성을 정의할 수 있도록 한다.

실제로 @Configuration 대신 @Component으로 바꾸고, 내부에 정의된 빈을 이용하여 또 다른 빈을 만들려고 시도하면 아래와 같이 에러가 나는 것을 알 수 있습니다.

Component

@Component 는 클래스 수준에서 빈을 정의하기 위해 사용되는 애노테이션이다.
해당 에너테이션이 붙어 있는 클래스는 컴포넌트의 대상이 되어 빈으로 등록됩니다.

마무리

@Bean 은 @Configuration과 함께 사용되어 메소드 레벨에서 직접 의존관계를 만든 후 빈으로 등록하고 싶은 경우에 사용합니다.
또 @Component는 클래스 수준에서 사용되는 에노테이션이기 때문에 외부에 있는 클래스나 라이브러리를 빈으로 등록할 때는 어쩔 수 없이 @Bean을 사용합니다.

클래스 단위에서 사용하고자 할 때는 @Component 사용하여 빈으로 등록합니다.

참고


https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html
https://docs.spring.io/spring-framework/reference/core/beans/java/bean-annotation.html
https://jojoldu.tistory.com/27

0개의 댓글