@Component 와 @Bean

김운채·2024년 3월 20일
0

Spring

목록 보기
6/10
post-thumbnail

스프링은 컨테이너에 Bean을 등록한다. 과거에는 xml에 bean을 작성해서 등록했는데 이젠 어노테이션으로 편리하게 등록할 수 있다.

스프링 MVC 패턴에서는 @Controller @Service @Repository 으로 손쉽게 스프링 컨테이너에 빈으로 저장할 수 있고, configuration 관련 객체들은 @Bean @Component 로 저장할 수 있다.

오늘은 @Bean@Component 이 두개를 알아보려 한당

@Component

@Component싱글톤 클래스 빈을 생성하는 어노테이션이다. 근데 @Scope("Prototype") 어노테이션을 붙여주면 싱글톤이 아닌 빈도 생성됨.
@Service, @Repository 같은 어노테이션이 여기에 포함된다.

@Component 어노테이션은 선언적(Declarative)인 어노테이션이다.
그냥 쉽게 말해서 "야야 여기 클래스 빈으로 등록해줘~~" 라는 뜻임.
스프링은 스캔할 패키지를 검색해서 @Component어노테이션을 발견하면 등록한다.

@Bean

@Bean은 주로 @Configuration 어노테이션이 들어간 클래스 내의 메소드에 선언한다.

그냥 싹다 @Component로 통일하면 안되나 싶어서 찾아본 이놈의 역할은 이 @Bean을 통해서 유연하게 빈 등록이 가능하다는 것이다.

예전 스프링은 XML설정만 가능했다.(물논 지금도 XML설정을 지원하긴함)
이 XML 설정의 장점은 빈을 넣었다 뺐다 하면서 유연한 설정이 가능하다는 것이다. 필요없는 빈은 주석처리해버리고 앱 재시작하면 됨.
이렇게 스캔할 필요없이 바로 빈 등록이 가능한 부분이 @Bean으로도 가능하다.

// prop 정의 안하면 빈 문자열로. null 받으면 switch 문에서 NullPointerException 발생함
@Value("${my.prop.animal:}")
private String animal;

@Bean
public Animal animal() {
    switch(animal) {
        case "dog": return new Dog();
        case "cat": return new Cat();
        case "cow": return new Cow();
        default: throw new InvalidStateException("동물 정의하고 다시 실행할 것!");
    }
}

출처

이런식으로 프로퍼티 값을 읽어서 구현 클래스를 인터페이스 기반 빈에 등록해주는 유연한 처리가 가능하다.
또한, @Component 어노테이션 넣기 곤란한 타사 라이브러리 클래스를 빈에 등록할 때도 @Bean 어노테이션을 통한 메소드를 통해 등록할 수 있다.

@Component 와 @Bean의 차이

1. 선언위치의 차이

이 둘의 첫번째 차이는 선언위치의 차이다.

@Component class level에 선언되고 @Beanmethod 레벨에 선언된다.

패스워드 암호화를 위해서 Bcrypt를 사용하는 모듈을 Component로 제공한다고 하면 아래와 같이 class level@Component를 선언할 수 있다.

@Component
public class PasswordEncoder {
    public String encode(String seed) {
        return new BCryptPasswordEncoder().encode(seed);
    }

    public boolean matches(String seed, String password) {
        return new BCryptPasswordEncoder().matches(seed, password);
    }
}

@Component 위치에 @Bean을 사용한다면 IDE가 바로 지적해줌

@Bean메소드 레벨에 선언한다.
아래는 스프링 시큐리티를 사용했다면 익숙한 코드일 것이다.

Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public PasswordEncoder getPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

@Configuration

@Bean 을 붙이면 클래스 위에는 @Configuration을 붙여줘야한다.

아래와 같이 @Configuration 없이 @Bean 만 사용했다면,

public class MyBean {
    @Bean
    public PasswordEncoder getPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

이 Bean을 다른 곳에서 의존성 주입하는데 활용할 수 없다.

@Configuration을 사용하면 정상적으로 IoC 컨테이너에 등록되서 의존성 주입을 할 수 있다.

사실 Configuration 내부에 Component 어노테이션이 있다.

내부에 @Component가 붙어 있기 때문에, 메소드 레벨에 존재하는 @Bean도 spring이 인식하여 설정 정보 자체도 스프링 빈으로 자동으로 등록된다.

2. 사용법의 차이

@Bean외부 라이브러리가 제공하는 객체를 사용할 때 활용하고, @Component내부에서 직접 접근 가능한 클래스에 사용하면 된다.

@Component
public class PasswordEncoder {
    public String encode(String seed) {
        return new BCryptPasswordEncoder().encode(seed);
    }

    public boolean matches(String seed, String password) {
        return new BCryptPasswordEncoder().matches(seed, password);
    }
}

여기서 @Component를 쓸 수 있는건, 이 PasswordEncoder 클래스를 내가 직접 만들었기 때문이다. 그래서 개발자가 직접 컨트롤이 가능한 클래스들의 경우에는 @Component를 사용하면 된다. 이 코드가 라이브러리에 있는 코드였다면 @Component를 쓸 수 없다.

라이브러리에 있는 객체@Bean 을 써서 활용할 수 있다.
@Bean어노테이션은 개발자가 컨트롤이 불가능한 외부 라이브러리들을 Bean으로 직접 등록하고 싶은 경우에 사용 된다.

정리

@Bean@Component의 차이는 선언 위치, 그리고 사용법의 차이에 있다.

  • @Component자동으로 스프링 컨테이너에 스프링 빈을 등록하고, @Bean수동으로 스프링 컨테이너에 등록할 스프링 빈을 직접 등록한다.

  • @Component class level에 선언되고 @Bean method 레벨에 선언된다.

  • @Bean외부 라이브러리가 제공하는 객체를 사용할 때 활용하고, @Component 내부에서 직접 접근 가능한 클래스에 사용하면 된다.

  • 일반적인 빈 등록은 간편하게 @Component어노테이션으로, 유연한 빈 등록이 필요하다면 @Configuration 어노테이션이 들어간 클래스 내 @Bean 어노테이션 메소드 선언으로 사용한다.

0개의 댓글