1. 생성자 주입
2. 수정자 주입 (setter 주입)
3. 필드 주입
4. 일반 메서드 주입
@Component public class CoffeeService { private final MemberRepository memberRepository; private final CoffeeRepository coffeeRepository; @Autowired public CoffeeService(MemberRepository memberRepository, CoffeeRepository coffeeRepository) { this.memberRepository = memberRepository; this.coffeeRepository = coffeeRepository; } }
특징
- 생성자 호출 시점에 딱 1번만 호출되는 것이 보장
- 불변과 필수 의존 관계에 사용
- 생성자가 1개만 존재하는 경우에는 @Autowired를 생략해도 자동 주입
- NullPointerException 을 방지
- 주입받을 필드를 final 로 선언 가능
@Component public class CoffeeService { private MemberRepository memberRepository; private CoffeeRepository coffeeRepository; @Autowired public void setMemberRepository(MemberRepository memberRepository) { this.memberRepository = memberRepository; } @Autowired public void setCoffeeRepository(CoffeeRepository coffeeRepository) { this.coffeeRepository = coffeeRepository; } }
특징
- 선택과 변경 가능성이 있는 의존 관계에 사용
- 자바빈 프로퍼티 규약의 수정자 메서드(setter) 방식을 사용하는 방법
- 생성자 주입과 차이점은 생성자 대신 set필드명 메서드를 생성하여 의존 관계를 주입
- 수정자의 경우 @Autowired를 입력하지 않으면 실행이 되지 않는다.
- @Component가 실행하는 클래스를 스프링 빈으로 등록합니다.
- 스프링 빈으로 등록한 다음 의존 관계를 주입하게 되는데 @Autowired 있는 것들을 자동으로 주입하게 됩니다.
Q. 생성자는 1개일 때 @Autowired가 없어도 작동이 되는 이유는 뭘까요??
- 스프링이 해당 클래스 객체를 생성하여 빈에 넣어야하는데 생성할 때 생성자를 부를 수 밖에 없게 됩니다.
- 그렇기 때문에 빈을 등록하면서 의존 관계 주입도 같이 발생
@Component public class CoffeeService { @Autowired private MemberRepository memberRepository; @Autowired private CoffeeRepository coffeeRepository; }
특징
- 코드가 간결해서 예전에 많이 사용된 방식이지만, 외부에서 변경이 불가능하여 테스트하기 힘들다는 단점이 있습니다.
- DI 프레임워크가 없으면 아무것도 할 수 없습니다.
- 실제 코드와 상관 없는 특정 테스트를 하고 싶을 때 사용할 수 있습니다.
- 하지만 정상적으로 작동되게 하려면 결국 setter가 필요하게 되서 수정자 주입을 사용하는게 더 편리해집니다.
특징
- 한번에 여러 필드를 주입 받을 수 있습니다.
- 일반적으로 사용되지 않는다
주입할 스프링 빈이 없을 때 동작해야하는 경우가 있습니다.
@Autowired만 사용하는 경우 required 옵션 기본값인 true가 사용되어 자동 주입 대상이 없으면 오류가 발생하는 경우가 있을 수 있습니다.
스프링 빈을 옵셔널하게 해둔 상태에서 등록이 되지 않고, 기본 로직으로 동작하게 하는 경우
static class TestBean { @Autowired(required = false) public void setNoBean1(Member noBean1) { System.out.println("noBean1 = " + noBean1); } @Autowired public void setNoBean2(@Nullable Member noBean2) { System.out.println("noBean2 = " + noBean2); // noBean2 = null } @Autowired public void setNoBean3(Optional<Member> noBean3) { System.out.println("noBean3 = " + noBean3); // noBean3 = Optional.empty } }
※ 생성자 주입 방식의 장점 요약
- 의존관계 설정이 되지 않으면 객체생성이 불가능
- 컴파일 타임에 인지가 가능
- NPE 에러 방지가 가능
- 의존성 주입이 필요한 필드를 final 로 선언 가능
- (스프링에서) 순환참조 감지가 가능
- 순환 참조 시 앱구동이 실패하게 됩니다.
- 테스트 코드 작성 용이
- 수정자 주입이 필요한 경우가 있을 수 있지만 옵션이 필요할 때만 선택하면 됩니다.