Spring 기능 - DI ( Dependency Injection )

이정수·2025년 10월 17일

Spring

목록 보기
7/18

의존성 주입이 필요한 이유?

。한 Application에서 Web Layer, Business Layer, Data Layer가 각각 존재 시 각 Layer을 구성하는 Class들은 서로의 객체들을 필요로 한다.
Spring Framework은 각 Layer클래스Spring Bean으로 등록 및 dependency를 정의하여 의존객체Spring Bean을 주입
▶ 실제 application은 수천개의 dependency가 존재한다고 할 수 있다.

의존성 주입 ( DI : Dependency Injection )
객체가 의존하는 다른 객체를 직접 생성하지 않고 외부에서 주입받는 것

Spring ContextBean Registry 내 저장된 Spring Bean을 필요로 하는 의존객체의존성을 정의하여 Auto-Wiring하여 Spring Bean주입
의존성주입을 구현하지 않으면 의존객체에서 NPE 발생.

Spring Bean으로 등록한 Class에서 의존성 주입을 받을 수 있다.
@Component, @Configuration , ... 등으로 선언된 Class

Spring Bean의 제어권이 Spring에 있으므로 IoC 제공

  • 의존성 주입의 장점
    낮은 결합도 : ServiceRepository 구현체를 몰라도 된다.
    유지보수 용이 : DBMemory, JPA로 교체하더라도 Service소스코드 수정은 없음.
    테스트용이 : Mock객체 주입이 용이
    확장성 : 구현체 교체 시 소스코드 수정이 거의없어 구현체 추가 등 확장이 용이
    OCP 준수

  • Auto-Wiring :
    Spring Framework에서 Spring Bean의존성을 분석하여 올바른 의존객체를 자동으로 식별하여 주입하는 과정

    @Autowired :
    의존성 주입을 수행하는 어노테이션
    Spring Context에서 해당 의존객체Class Type에 해당하는 Spring Bean을 자동으로 선언된 Field, Setter주입 방식에 따라 의존성 주입을 수행

의존성 주입 방법
생성자 주입, 필드 주입, 세터 주입이 존재

  • 생성자 주입 ( Constructor-based DI )
    생성자를 사용하여 의존객체에 의존성을 정의하여 Spring Bean을 주입

    클래스생성자가 단 하나만 존재해야 @Autowired를 생략가능
    클래스생성자가 많은 경우 @Autowired를 명시적으로 선언

    。실무에서 가장 많이 사용
    초기화 이후 재할당이 불가능한 불변객체Spring Bean의존성주입이 적합한 방식이므로.
private final Dependency1 dependency1; // 불변변수
public YourBusinessClass(Dependency1 dependency1) {
        this.dependency1 = dependency1;
    }
  • 필드 주입 ( Field-based DI ) :
    의존객체Field@Autowired 선언하여 의존성을 정의하여 Spring Bean을 주입

    Java Reflection을 통해 주입하므로 final을 선언한 불변객체에는 의존성 주입을 수행할 수 없다.
    ▶ 주로 테스트코드 적용 시 활용
    Java Reflection
@Autowired
Dependency1 dependency1;
  • Setter 주입 ( Setter-based DI )
    의존객체setter method@Autowired를 선언하여 의존성을 정의하여 Spring Bean 주입
    Setter 자체가 비추천되는방식이므로 사용되진 않는다.
private Dependency1 dependency1;
@Autowired
public void setDependency1(Dependency1 dependency1) {
        this.dependency1 = dependency1;
    }

인터페이스 구현체클래스의존성 주입Spring Context 내 이를 상속하거나 구현하는 복수의 Spring Bean이 존재 시 사용하는 방법
의존객체의존성주입을 수행하기위해 클래스 또는 인터페이스 구현체에 해당하는 Spring Bean을 찾을때 Spring Context 내 해당 클래스 또는 인터페이스를 상속하거나 구현한 복수의 클래스Spring Bean이 등록되있는 경우 어떤 Spring Bean으로 가져와야 할지 설정이 필요

@Primary, @Qualifier, 이름주입, PSA , 프로필의 방법이 존재
PSA소스코드를 변경하지않고 Configuration file을 통해 특정 Spring Bean을 사용하도록 설정 PSA
프로필의 경우도 특정 프로필활성화하는 방법으로 특정 Spring Bean을 사용하도록 설정 프로필

  • @Primary :
    Spring Bean으로 등록되고 동일한 Class or Interface를 상속받은 클래스 중 우선적으로 의존성 주입을 수행할 클래스에 선언하여 우선권을 부여하는 어노테이션
    Candidate Bean 중 해당 ClassSpring Bean을 우선적으로 의존성 주입

  • @Qualifier("스프링빈Class명") :
    Spring Bean 주입 시 주입할 Spring Bean Class명을 선언하여 해당 명칭의 Spring Bean주입하도록하는 어노테이션
    @Qualifier@Primary보다 더 높은 우선순위를 지님.

    의존객체DI가 수행되는 생성자 매개변수@Qualifier("스프링빈Class명")을 선언
    @Qualifier를 통해 해당 명칭의 Class TypeSpring Bean이 자동으로 주입
    Spring Bean을 정의하는 Class에도 추가적으로 Qualifier("사용자정의명칭") 선언 시 클래스명이 아닌 사용자정의명칭으로 식별하여 Spring Bean 주입

  • 이름주입
    。단순히 생성자 매개변수 이름을 SpringBean명으로 명시적으로 설정 시 해당 명칭의 Spring BeanContextBean Registry에서 찾아서 자동으로 주입
    SpringBean명 : String Bean 클래스명카멜케이스
interface GamingConsole{
    String up();
}
@Component
@Primary
class MarioGame implements GamingConsole{
    public String up(){
        return "Mario goes upside";
    }
}
@Component
@Qualifier("wjdtn")
class SuperContraGame implements GamingConsole{
    public String up(){
        return "Character goes upside";
    }
}
@Component
class Runner {
    private final GamingConsole gc1;
    private final GamingConsole gc2;
    private final GamingConsole gc3;
    public Runner(GamingConsole gc1 , @Qualifier("wjdtn") GamingConsole gc2 , GamingConsole marioGame){
        this.gc1 = gc1; // @Primary
        this.gc2 = gc2; // @Qualifier
        this.gc3 = marioGame; // 이름주입
    }
    public void run(){
        System.out.println(gc1.up()); // Mario goes upside
        System.out.println(gc2.up()); // Character goes upside
        System.out.println(gc3.up()); // Mario goes upside
    }
}
  
profile
공부기록 블로그

0개의 댓글