[Spring-기본] 의존관계 자동 주입

DANI·2023년 11월 25일

Spring[김영한T]

목록 보기
25/31
post-thumbnail

📕 다양한 의존관계 주입 방법

  • 생성자 주입
  • 수정자 주입(setter 주입)
  • 필드 주입
  • 일반 메서드 주입


📑 생성자 주입

@Component
public class OrderServiceImpl implements OrderService{

    private MemberRepository memberRepository;
    private DiscountPolicy discountPolicy;

    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
}

✅ 생성자를 통해 주입 하는 방법

  • 생성자 호출 시점에 딱 1번만 호출되는 것이 보장됨
  • 불변, 필수 의존관계에 사용

✨ 생성자가 딱 1개만 있을 땐 @Autowired를 생략해도 된다.



📑 수정자 주입(setter 주입)

@Component
public class OrderServiceImpl implements OrderService{

    private MemberRepository memberRepository;
    private DiscountPolicy discountPolicy;

    @Autowired
    public void setMemberRepository(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
  
    @Autowired
    public void setDiscountPolicy(DiscountPolicy discountPolicy) {
        this.discountPolicy = discountPolicy;
    }
}

✅ 수정자를 통해 주입 하는 방법

  • 자바빈 프로퍼티 규약의 수정자 메서드 방식을 사용하는 방식
  • 선택, 변경의 가능성이 있는 의존관계에 사용

@Autowired 는 주입할 대상이 없으면 오류가 발생한다. 주입할 대상이 없어도 동작하게 하려면 @Autowired(required = false)로 지정한다.



📑 필드 주입

@Component
public class OrderServiceImpl implements OrderService{
    
    @Autowired
    private MemberRepository memberRepository;
    @Autowired
    private DiscountPolicy discountPolicy;

    }

✅ 필드를 통해 주입 하는 방법

  • 외부에서 변경이 불가능해서 테스트하기 힘들다
  • DI 프레임워크가 없으면 아무것도 할 수 없다
  • @Configuration과 같은 곳에서만 특별한 용도로 사용

✨ 사용하지 말자!



📑 일반 메서드 주입

@Component
public class OrderServiceImpl implements OrderService{

    private MemberRepository memberRepository;
    private DiscountPolicy discountPolicy;

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

✅ 일반 메서드를 통해 주입 하는 방법

  • 한 번에 여러 필드를 주입받을 수 있다.

@Autowired 는 스프링 컨테이너가 관리하는 스프링 빈이어야 동작한다. 예를들어, 스프링 빈으로 등록하지 않았던 Member와 같은 클래스에서는 @Autowired가 동작하지 않는다.





📕 옵션처리

  • @Autowired(required=false) : 자동 주입할 대상이 없으면 메서드 호출 X
  • @Nullable : 자동 주입할 대상이 없으면 null 입력
  • Optional<> : 자동 주입할 대상이 없으면 Optional.empty가 입력된다.

💾 OptionTest

package hello.core;

import hello.core.member.Member;
import jakarta.annotation.Nullable;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


import java.util.Optional;

public class OptionTest {

    @Test
    void OptionTest(){
    ApplicationContext ac = new AnnotationConfigApplicationContext(TestBean.class);
    }
    static class TestBean{

        @Autowired(required = false)
        public void setNoBean1(Member member){
            System.out.println("noBean1 = " + member);
        }

        @Autowired
        public void setNoBean2(@Nullable Member noBean2){
            System.out.println("noBean2 = " + noBean2);
        }

        @Autowired(required = false)
        public void setNoBean3(Optional<Member> member){
            System.out.println("noBean3 = " + member);
        }
    }
}

🔵 실행 결과




🚫 에러 발생

method setNoBean1(hello.core.member.Member) is already defined in class hello.core.OptionTest.TestBean

이미 메서드가 정의되어 있다는 에러가 발생했다.. 이상하다..

🔑 해결방안

package hello.core;

import hello.core.member.Member;
import jakarta.annotation.Nullable;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


import java.util.Optional;

public class OptionTest {

    @Test
    void OptionTest(){
    ApplicationContext ac = new AnnotationConfigApplicationContext(TestBean.class);
    }
    static class TestBean{

        @Autowired(required = false)
        public void setNoBean1(Member member){
            System.out.println("noBean1 = " + member);
        }

        @Autowired
        public void setNoBean1(@Nullable Member noBean2){
            System.out.println("noBean2 = " + noBean2);
        }

        @Autowired(required = false)
        public void setNoBean3(Optional<Member> member){
            System.out.println("noBean3 = " + member);
        }
    }
}

`setNoBean1` 메서드 이름을 중복해서 정의했다.. 메서드를 복붙하다보니 이런 오류가..😅





✨ 생성자 주입을 사용하는 것이 좋다✨

❓ why? 불변(생성자 주입을 사용 해 변경을 방지할 수 있음), 누락(final 키워드 사용)

  • 생성자 주입 방식을 선택하는 이유는 여러가지가 있지만, 프레임워크에 의존하지 않고, 순수한자바 언어의 특징을 잘 살리는 방법
  • 기본으로 생성자주입을 사용하고, 필수값이 아닌 경우에는 수정자주입방식을 옵션으로 부여하면 된다. 생성자주입과 수정자주입을 동시에 사용할 수 있다.

0개의 댓글