본문 바로가기

CS/Spring

의존관계 주입 방법 4가지

반응형

의존관계 주입 방법 4가지

 

생성자 주입 방법

생성자를 통해서 의존 관계를 주입받는 방식으로 애플리케이션이 시작 후 생성자 호출 시점에 딱 1번만 호출되는 것이 보장되며 불변(final), 필수(notNull) 의존관계에 사용된다. 

+ 생성자 주입을 기본으로 사용하고, 필수 값이 아닌 경우에는 수정자 주입 방식을 옵션으로 부여하여, 생성자 주입과 수정자 주입을 동시에 사용할 수 있다.

@Component
public class MemberServiceImpl implements MemberService{

    private final MemberRepository memberRepository; // = new MemoryMemberRepository();

    @Autowired
    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
}

생성자가 1개만 존재한다면 @Autowired를 생략해도 자동 주입이 된다.(spring) 

생성자 주입은 빈을 등록 시 의존관계 주입도 같이 일어난다.

 

수정자 주입 방법(Setter)

setter라 불리는 필드의 값을 변경하는 수정자 메서드를 통해서 의존관계를 주입하는 방법으로 선택, 변경 가능성이 있는 의존관계에 주로 사용되고 Java Bean 프로퍼티 규약의 수정자 메서드 방식을 사용한다.

spring에서 @Compnent를 컨테이너에 Bean을 등록 후 @Autowired가 들어간 부분을 찾아 (연관관계를 찾아) 의존관계를 주입한다. 

@Component
public class MemberServiceImpl implements MemberService{

    private MemberRepository memberRepository; // = new MemoryMemberRepository();
	
    @Autowired
    public void setMemberRepository(MemberRepository memberRepository){
        this.memberRepository = memberRepository;
    }
}

@Autowired가 없다면 Bean 등록이 이뤄지지 않는다. (@Autowired의 기본 동작은 주입할 대상이 없으면 오류가 발생하므로 주입할 대상이 없어도 동작하게 하려면 @Autowied(required = false)로 지정해야 한다.)

 

필드 주입 방법

의존관계를 필드에서 바로 주입하는 방법으로 간결한 코드로 의존관계를 주입할 수 있지만 외부에서 변경이 불가능하고 테스트하기 힘들다는 치명적인 단점이 존재한다. Test를 진행하기 위해서 코드를 수정하다 보면 어느새 수정자 주입 방법을 사용하게 될 수 도 있다. DI 프레임워크가 없다면 아무것도 할 수 없다. 비추(스프링 설정을 목적으로 하는 @Configuration 같은 곳에서만 특별한 용도로 사용)

@Component
public class MemberServiceImpl implements MemberService{

    @Autowired 
    private MemberRepository memberRepository; // = new MemoryMemberRepository();
	
}

 

일반 메서드 주입

일반 메서드를 통해서 의존관계를 주입받으며 한 번에 여러 필드를 주입받을 수 있지만 일반적으로 잘 사용하진 않는다.

@Component
public class MemberServiceImpl implements MemberService{

    private MemberRepository memberRepository; // = new MemoryMemberRepository();

    @Autowired
    public void init(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
}

일반 자바 객체에서 사용하면 오류가 발생하고 스프링 컨테이너가 관리하는 스프링 빈 안에서만 작동한다.

 

@Autowired란?

필요한 의존 객체의 타입에 해당하는 빈을 찾아 주입한다.

 

@Autowired 의존관계 주입에서 오류를 해결하는 방법 3가지

  • @Autowired(required=false)를 사용하여 주입할 대상이 없으면 수정자 메서드 자체를 호출하지 않는다. (default = true)
  • @Nullable을 사용하여 주입할 대상이 없다면 null을 반환한다.
  • Optional <>을 사용하여 주입할 대상이 없으면 Optional.empty를 반환한다.
class TestBean{
    @Autowired(required = false)
    public void setNoBean1(Member member){
        System.out.println("member = " + member);
    }
    @Autowired
    public void setNoBean2(@Nullable Member member){
        System.out.println("member = " + member);
    }
    @Autowired(required = false)
    public void setNoBean3(Optional<Member> member){
        System.out.println("member = " + member);
    }
}

결과 (Member는 스프링 빈이 아니다.)

Member 클래스는 Bean으로 등록이 되어있지 않아 작동하지 않는 것이 정상이다.

member = null
member = Optional.empty

 

생성자 주입 방법을 추천하는 이유

 

불변

  • 대부분의 의존관계 주입은 한번 일어나면 애플리케이션 종료 시점까지 의존관계가 변경(final)되지 않는다. (의존관계가 변경되면 위험)
  • 수정자 주입을 사용하면, setXxx 메서드를 public으로 열어두어야 하며 누군가(협업하는 다른 개발자)의 실수로 해당 메서드를 잘못 수정할 수 있다.(변경되면 안 되는 메서드를 public으로 열어두는 것은 좋은 설계 방식이 아니다.)
  • 생성자 주입은 객체를 생성할 때 딱 1번만 호출되므로 이후에 호출될 일이 없어 안전하다.

누락

  • 프레임워크 없이 순수한 자바 코드를 단위 테스트를 구현할 경우 생성자 주입을 통해서 의존관계가 주입되어 있다면 컴파일 단계에서 오류가 발생해서 개발자가 빠르게 수정이 가능하다.
  • 프레임워크에 의존하지 않고 순수한 자바 언어의 특징을 잘 살린 방법이다.
  • 기본으로 생성자 주입을 사용하고, 필수 값이 아닌 경우에는 수정자 주입 방식을 옵션(@Autowired(required=false))으로 부여하면 생성자 주입과 수정자 주입을 동시에 사용할 수 있다.
  • 생성자 주입 방식만이 final을 사용할 수 있다.
  • 생성자 주입을 사용하면 컴파일 단계에서 오류를 확인할 수 있다. (객체를 생성했을 때 주입되는 코드가 없다면 IDE에서 자동으로 오류를 잡아준다!)
  • 수정자 주입의 경우 컴파일 오류가 나지 않고 실행했을 때 수정자로 의존관계가 주입이 되어있지 않다면 NullPointerException 오류가 발생한다.

필드 인젝션을 사용하지 않게 된 이유 

SRP위반 (Single Responsibility Principal)

필드 인젝션은 @Autowired만을 사용하여 의존관계를 주입하는데 어떠한 조건도 없이 의존관계를 주입해주어 개발자가 어떤 의존성이 추가되는지와 유지보수 관점에서 수정해야 할 일이 생기면 수정하지 못하는 상황이 발생한다. 또한 Spring Boot 2.6 버전 이후로는 순환 참조를 허용하지 않게 변경되면서 2.5 버전까지 필드 주입으로 사용하다 2.6 이후 버전으로 마이그레이션 시 순환 참조를 허용하지 않아 문제가 발생할 수 있다.

 

의존성 주입의 장점

1. 컴포넌트 간의 결합도 감소, 직접 의존하는 객체를 생성하거나 인스턴스화하지 않기 떄문에, 코드를 변경하지 않아도 의존 객체를 교체하거나 수정할 수 있다.

2. 테스트 용의성, 의존성 주입을 통해 테스트할 때, 테스트용 객체를 주입하여 의존성이 있는 객체를 테스트하기 편해진다.

3. 단일 책임 원칙 준수, 의존성 주입은 객체 간의 관심사를 분리가 용의하다.

4. 반전 제어, 객체가 자신의 의존성을 결정하고 생성하는 것이 아니라 외부에서 의존성을 주입받아 사용이 가능하다.

 

반응형

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

Spring Bean 알아보기  (0) 2024.05.31
DataSource 알아보기  (1) 2024.03.31
Connection Pool 이해하기  (3) 2024.03.23
Spring MVC과 관심사 분리  (1) 2024.03.17
h2 DB에서 mysql로 변경하기  (1) 2022.12.03