스프링 의존성 주입

mangez_js·2024년 11월 27일

Study

목록 보기
12/47

의존성 주입(Dependency Injection, DI)이란?

객체 간의 의존 관계를 개발자가 아닌 스프링 컨테이너(IOC 컨테이너) 가 관리하고 주입해주는 설계 패턴
스프링의 핵심 개념인 제어의 역전(Inversion of Control, Ioc) 의 구현 방식 중 하나

의존성 주입을 해야 하는 이유

  • 테스트가 용이해진다.
  • 코드 재사용율이 높아진다.
  • 객체 간의 의존성을 줄이거나 없앨 수 있다.
  • 객체 간의 별합도를 낮추면서 유연한 코드를 작성할 수 있다.

DI를 구현하는 방식

1) 생성자 주입(Constructor Injection)

  • 생성자를 통해서 의존관계를 주입 받는 방법이다.
  • 생성자에 @Autowired를 붙여 의존성을 주입받을 수 있다.
    ∘ 클래스의 생성자가 하나이고, 그 생성자로 주입받을 객체가 빈으로 등록되어 있다면 @Autowired를 생략 할 수 있다.
  • 스프링 컨테이너가 올라오고 애플리케이션이 세팅되는 시점에 생성자 주입을 통해 한번만 호출 되는 것이 보장된다.
    ∘ final을 사용할 수 있다 -> '불변, 필수' 의존관계에서 사용된다.
  • 대부분의 의존관계 주입은 한번 설정이 되고 나면 의존관계를 변경할 일이 없다.
@Component
public class Service {
    private final Repository repository;

    // 생성자를 통한 의존성 주입
    @Autowired
    public Service(Repository repository) {
        this.repository = repository;
    }
}

2) Setter 주입(Setter Injection)

  • 객체의 Setter 메서드를 통해 의존성을 주입.
  • 선택적 의존성을 처리할 때 유용하지만, 객체가 생성 후에도 상태가 변경될 가능성이 있음.
@Component
public class Service {
    private Repository repository;

    // Setter를 통한 의존성 주입
    @Autowired
    public void setRepository(Repository repository) {
        this.repository = repository;
    }
}

3) 필드 주입(Field Injection)

  • 객체의 필드에 직접 의존성을 주입(필드에 @Autowired 어노테이션을 붙여주면 자동으로 의존성 주입이 된다.)
  • 사용법이 간단해서 많이 접할 수 있는 방법이다.
  • 단점
    ∘ 외부에서 변경이 불가능 하기 때문에 테스트하기 힘들다.
    ∘ 코드가 간결하지만 외부에서 변경하려면 setter를 만들어야 한다.
    ∘ 생성자 주입과 다르게 final을 선언할 수 없어서, 객체를 변할 수 있다.
@Component
public class Service {
    @Autowired
    private Repository repository;
}

DI를 설정하는 방법

1) XML 기반 설정

applicationContext.xml 파일을 통해 설정

<bean id="service" class="com.example.Service">
    <property name="repository" ref="repository" />
</bean>
<bean id="repository" class="com.example.Repository" />

2) Java Config 기반 설정

Java 클래스에서 @Configuration@Bean으로 설정

@Configuration
public class AppConfig {
    @Bean
    public Service service() {
        return new Service(repository());
    }
@Bean
public Repository repository() {
    return new Repository();
}

}


3) Annotation 기반 설정
> `@Component`와 `@Autowired`를 활용
```java
@Component
public class Repository {}

@Component
public class Service {
    private final Repository repository;

    @Autowired
    public Service(Repository repository) {
        this.repository = repository;
    }
}

권장되는 주입 방식

Spring Framework reference에서 권장하는 방법은 생성자를 통한 주입이다.

생성자 주입을 권장하는 이유

필수적으로 사용해야하는 의존성 없이는 Instance를 만들지 못하도록 강제할 수 있기 때문이다.

  • 순환 참조를 방지할 수 있다.
    ∘ 의존 관계에 내용을 외부로 노출 시킴으로써 컴파일 시점에 오류를 체크할 수 있따.
  • 불변성을 유지한다.
    ∘ 생성자로 의존성을 주입할 때 final로 선언할 수 있고, 이로 인해 런타임에서 의존성을 주입받는 객체가 변할 일이 없어진다.
    ∘ 그래서 누군가 Controller 내부에서 Service 객체를 바꿔치기 할 수 없다.
  • 테스트에 용이하다.
    ∘ DI의 핵심은 관리되는 클래스가 DI 컨테이너에 의존성이 없어야 한다.
    ∘ 메인 코드가 필드 주입으로 작성된 경우, 순수 자바 코드로 단위 테스트를 실행하는 것은 불가능하다.
    ∘ 메인 코드는 Spring 같은 DI 프레임워크 위에서 동작하지만, 테스트 코드는 그렇지 않아서 의존관계 주입이 null 상태여서 NullPointError이 발생한다.
    ∘ 즉, 독립적으로 인스턴스화가 가능한 POJO(Plain Old Java Object)여야 한다는 것이다.

0개의 댓글