본문 바로가기

Programming/Spring

[Spring] Bean 주입하기 : DI

스프링에서는 객체의 생성과 소멸 등에 대한 제어를 컨테이너가 관리하고 필요할 때 주입을 받아 사용하게 된다.

 

DI 방법

 1. 생성자 기반 주입

종속성을 나타내는 인수로 생성자를 호출하는 컨테이너에 의해 수행된다. 컨테이너가 알아서 생성자에게 객체를 넣어주면서 생성하게 된다. 생성자의 파라미터를 통해 의존 관계를 파악하기 쉽다는 장점이 존재한다.

 

public class SimpleMovieLister {
    private final MovieFinder movieFinder;

    public SimpleMovieLister(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}

 

클래스에 생성자가 한 개만 존재하고 매개 변수 타입이 빈으로 등록되어 있다면 사용이 가능하다. lombok을 사용한다면 @RequiredArgsConstructor 애노테이션을 클래스에 붙이면 자동으로 final 필드들을 가진 생성자를 만들어 주기 때문에 쉽게 작성이 가능하다.

 

2. setter 기반 주입

인수가 없는 생성자를 호출한 후 빈에서 setter를 호출해 주입하는 방식이다. 

 

public class SimpleMovieLister {
    private MovieFinder movieFinder;

    @Autowired
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}

 

3. 필드 주입

public class SimpleMovieLister {
    
    @Autowired
    private MovieFinder movieFinder;

}

 

 

 

💡 어떤 주입 방식을 사용할까?

생성자 기반 DI와 setter기반 DI를 혼합해 사용할 수 있기 때문에 필수적 종속성에서는 생성자를 사용하고 선택적인 종속성은 setter 기반 주입을 추천한다고 한다.

setter기반에서도 @Required를 사용한다면 필수 종속성으로 만들 수 있지만 필수 종속성을 파악하기 편하도록 생성자를 통한 주입을 하는 것이 좋다. 또한, 중간에 값이 변경될 위험이 존재하기도 한다.

생성자를 통해 구현하면 변경이 불가능한 객체로 생성되지만, Setter 주입은 해당 클래스 개체를 나중에 재구성하거나 다시 주입할 수 있다는 장점이 존재한다. 

하지만, Setter가 없을 때에는 굳이 코드를 작성하기 번거롭다면 필드 주입을 사용해도 좋다고 한다.

추천 순위 : 생성자 > Setter > 필드 

 

 


❓ 만약 주입의 대상이 되는 객체가 여러 개라면?

만약 주입의 대상 클래스를 상속받아 구현하는 클래스가 여러 개라면 스프링에서는 어떤 객체로 주입을 해야할 지 알 수 없어 에러가 발생하게 된다.

 

1. @Primary

대상이 되는 클래스 주입하고 싶은 클래스에 @Primary 애노테이션을 붙이게 되면 스프링이 자동으로 해당 객체를 주입해준다.

 

@Component
@Primary
public class MyMovieRepository implements MovieRepository {
}

 

2. @Qualifier

주입하는 곳에서 @Qualifier 애노테이션을 통해 지정할 수도 있다. 애노테이션의 value에 주입을 원하는 빈의 클래스 명을 lowerCamelCase로 입력하면 된다.

 

public class MovieService {

    @Autowired
    @Qulifier("myMovieRepository")
    private MovieRepository movieRepository;
    
}

 

3. 모든 빈을 주입받기

만약 대상이 되는 객체들이 모두 필요하다면 모든 객체를 받아 사용할 수도 있다.

 

public class MovieService {

    @Autowired
    private List<MovieRepository> movieRepositories;
    
}

 

 

4. 필드 이름으로 지정하기

추천하는 방법은 아니지만 필드의 이름을 주입하고 싶은 클래스명과 동일하게 지정하면 해당 객체를 주입받을 수 있다.

 

public class MovieService {

    @Autowired
    private MovieRepository myMovieRepository;
    
}

 

 


📚 Reference

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html
[인프런] 스프링 프레임워크 핵심 기술 / 백기선

 

 

'Programming > Spring' 카테고리의 다른 글

[Spring] AOP, Spring AOP  (0) 2021.04.30
[Spring] Bean Scope와 주의할 점  (0) 2021.04.22
[Spring] Bean을 등록하는 방법  (0) 2021.04.22