Post

[Spring] 스프링 빈(Bean), 의존성 주입(DI)에 관해서

Bean

스프링 빈(Spring Beans)은 스프링 프레임워크에서 객체를 관리하는 핵심 요소이다. 이들은 스프링의 IoC(제어의 역전)컨테이너에 의해 인스턴스화 되고, 조립되며, 관리된다. 빈은 스프링 애플리케이션의 기본 구성요소이며, 주로 서비스, 레포지토리, 컨트롤러 등의 역할을 수행한다.

관련 Annotation

@Bean

해당 어노테이션은 메소드 레벨에서 사용되며, 반환되는 스프링 컨테이너에 빈으로 등록한다. 주로 설정 클래스에서 사용되며, 개발자가 직접 생성 및 관리 해야하는 객체에 사용된다.

1
2
3
4
5
6
7
8
9
10
11
@Configuration
public class AppConfig {
    @Bean
    public MyBean myBean() {
        return new MyBean();
    }
}

public class MyBean {
    // 빈으로 사용될 클래스의 내용
}

@Component

해당 어노테이션은 클래스 레벨에서 사용되며, 해당 클래스를 스프링 빈으로 자동 등록한다. ‘@Service, @Repository, @Controller’와 같은 다른 어노테이션들은 ‘@Component’를 내부에 가지고 있는 ‘@Component’의 특별한 형태로, 특정 레이어의 컴포넌트를 명시한다.

1
2
3
4
@Component
public class MyComponent {
    // 자동으로 빈으로 등록될 클래스의 내용
}

@ComponentScan

해당 어노테이션은 스프링에서 특정 패키지를 스캔하도록 지시하며 '@Component' 어노테이션이 붙은 클래스들을 찾아 빈으로 등록하도록한다.

1
2
3
4
5
@Configuration
@ComponentScan("com.example.myapp")
public class AppConfig {
    // 다른 빈 정의
}

@Primary

여러 빈이 같은 타입에 대해 후보가 될 때 ‘@Primary’어노테이션이 붙은 빈을 우선적으로 사용하도록 스프링에게 지시한다. 이는 의존성 주입 시 자동 와이어링에서 사용되는 기본 빈을 명시하는 데 유용하다.

1
2
3
4
5
6
7
8
9
10
@Service
@Primary
public class PrimaryService implements MyService {
    // 기본 서비스로 사용될 클래스의 내용
}

@Service
public class SecondaryService implements MyService {
    // 다른 서비스 구현
}

@Qualifier

동일한 타입의 여러 빈이 있을 때, 특정 빈을 명확하게 지시하고자 할 때 사용한다. ‘@Autowired’와 함께 사용되어 주입할 빈의 이름을 명시적으로 지정할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Service
public class MyService {
    private final MyComponent myComponent;

    @Autowired
    public MyService(@Qualifier("specificComponent") MyComponent myComponent) {
        this.myComponent = myComponent;
    }
}

@Component("specificComponent")
public class SpecificComponent implements MyComponent {
    // 특정 구현
}

@Bean vs @Component

  • 선언 위치: ‘@Bean’은 메서드에, ‘@Component’는 클래스에 선언된다.
  • 사용 목적: ‘@Bean’은 주로 외부 라이브러리나 복잡한 생성 로직이 필요한 객체에 사용되고, ‘@Component’는 개발자가 직접 정의한 클래스에 사용된다.
  • 제어 정도: ‘@Bean’은 객체 생성과 관리에 대한 제어가 더 세밀하며, ‘@Component’는 스프링이 자동으로 처리한다.

@Primary vs @Qualifier

  • 적용 범위: ‘@Primary’는 빈 정의에 사용되며, 기본 빈을 지정한다. ‘@Qualifier’는 주입 받는 쪽에서 사용되며, 주입될 특정 빈을 지정한다.
  • 사용 목적: ‘@Primary’는 일반적인 상황에서 기본적으로 사용될 빈을 지정하는 반면, ‘@Qualifier’는 특정상황에서 필요한 특정 빈을 세밀하게 지정하는 데 사용된다.
  • 유연성: ‘@Qualifier’는 ‘@Primary’보다 더 유연한 선택이 가능하며, 동일한 타입의 여러 빈 중에서 특정 빈을 선택할 수 있다.

의존성 주입(Dependency Injection)

의존성 주입은 객체 간의 의존 관계를 외부에서 설정하는 디자인 패턴이다. 이를 통해 객체는 자신이 필요로 하는 의존성을 직접 생성하거나 검색하지 않고, 외부로 부터 제공받는다.

의존성 주입 방식

스프링 프레임워크에서는 주로 세 가지 방식의 의존성 주입을 지원한다.

생성자 기반 (Constructor-based)

  • 객체가 생성될 때 생성자를 통해 의존성이 주입
  • 생성자 주입은 필요한 의존성이 반드시 제공되어야 객체가 생성될 수 있기 때문에, 불안정한 상태의 객체가 생성되는 것을 방지한다.
  • 의존성이 불변하게 설정되며, 순환 참조를 방지하는데 도움이 된다.
1
2
3
4
5
6
7
8
9
@Component
public class MyService {
    private final MyRepository repository;

    @Autowired
    public MyService(MyRepository repository) {
        this.repository = repository;
    }
}

수정자 기반 (Setter-based)

  • 객체 생성 후, setter 메소드나 다른 수정 메소드를 통해 의존성을 주입한다.
  • 선택적인 의존성이나, 변경 가능한 의존성에 적합하다.
  • 의존성 주입 후에도 객체의 상태를 변경할 수 있다.
1
2
3
4
5
6
7
8
9
@Component
public class MyService {
    private MyRepository repository;

    @Autowired
    public void setRepository(MyRepository repository) {
        this.repository = repository;
    }
}

필드 기반 (Field)

  • 클래스 내의 필드에 직접 의존성을 주입한다.
  • 순환 참조의 위험이 있고, 의존성이 명시적이지 않을 수 있다.
1
2
3
4
5
@Component
public class MyService {
    @Autowired
    private MyRepository repository;
}

Which one should you use?

스프링에서 의존성 주입은 생성자 기반 주입 방식을 가장 권장한다.

@Autowired

해당 어노테이션은 스프링 프레임워크에서 의존성 주입(Dependency Injection)을 자동으로 처리하기 위해 사용됩니다. 이 어노테이션은 스프링 컨테이너에게 필요한 의존성을 자동으로 연결하도록 지시한다. ‘@Autowired’는 코드를 간결하게 하고, 의존성을 관리를 편리하게 해준다. 그러나 적절한 방법을 사용하여 의존성의 명확성과 테스트 용이성을 보장하는 것이 중요하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 생성자 주입
@Component
public class MyService {
    private final MyRepository repository;

    @Autowired
    public MyService(MyRepository repository) {
        this.repository = repository;
    }
}

// 세터 주입
@Component
public class MyService {
    private MyRepository repository;

    @Autowired
    public void setRepository(MyRepository repository) {
        this.repository = repository;
    }
}

// 필드 주입
@Component
public class MyService {
    @Autowired
    private MyRepository repository;
}
This post is licensed under CC BY 4.0 by the author.

© chanho. Some rights reserved.