예제에서 사용한 모든 코드는 Github Repository 에 있습니다.
스프링으로 개발하다 보면 필요한 객체들은 스프링 컨테이너에서 관리하는 빈으로 등록하여 사용할 경우가 생깁니다.
이때 @Congiguration 설정과 함께 원하는 의존관계를 만족하는 인스턴스를 반한하도록 하는 메서드를 만든 후 그 위해 @Bean 애노테이션을 선언하여 만듭니다. 혹은 필요한 클래스 위에 @Componet 를 선언하여 사용하기도 합니다.
주로 @Configuration 과 함께 @Bean 쓰이고, 왜 @Component 는 같이 안썻던걸까?
그리고 @Bean 과 @Component 는 어떤 차이가 있는 걸까?
@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 는 클래스 수준에서 빈을 정의하기 위해 사용되는 애노테이션이다.
해당 에너테이션이 붙어 있는 클래스는 컴포넌트의 대상이 되어 빈으로 등록됩니다.
@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