Construcotr(생성자)

public  class  ExampleCase{

	private  final  ChocolateService  chocolateService;
	
	private  final  DrinkService  drinkService;

	@Autowired
	public  ExampleCase(ChocolateService  chocolateService, DrinkService  drinkService){
		this.chocolateService = chocolateService;
		this.drinkService = drinkService;
	}
}

Setter

public  class  ExampleCase{
	private  ChocolateService  chocolateService;

	private  DrinkService  drinkService;

	@Autowired
	public  void  setChocolateService(ChocolateService  chocolateService){
		this.chocolateService = chocolateService;
	}

	@Autowired
	public  void  setDrinkService(DrinkService  drinkService){
		this.drinkService = drinkService;
	}

}

 Field

 

public  class  ExampleCase{

	@Autowired
	private  ChocolateService  chocolateService;

	@Autowired
	private  DrinkService  drinkService;
}

3개의 코드를보면 Field Injection이 심플하고 간편해보인다. 하지만 Spring 4.3부터는 대부분 Contructor Inject을 추천한다.

 

Field Injection을 추천하지않는 이유

 

 

단일 책임의 원칙 위반

 의존성을 주입하기가 쉽다. @Autowired 선언 아래 여러개를 막 추가 할 수가 있다. 하지만 Constructor Injection을 사용하면 다른 Injection 타입에 비해 위기감을 느끼게 해준다. Constructor의 파라미터가 많아짐과 동시에 하나의 클래스가 많은 책임을 떠안는다는 걸 알 수 있다. 이러한 징조들이 리팩토링을 해야한다는 신호가 될 수 있다.

 

의존성이 숨는다.

 DI(Dependecy Injection) 컨테이너를 사용한다는 것은 클래스가 자신의 의존성만 책임진다는게 아니다. 제공된 의존성 또한 책임진다. 그래서 클래스가 어떤 의존성을 책임지지 않을 때, 메서드나 생성자를 통해 (Setter나 Construcotr)이 확t실하게 커뮤니케이션이 되어야한다. 하지만 Field Injection은 숨은 의존성만 제공해준다.

 

DI 컨테이너의 결합성과 테스트 용이성

DI 프레임워크의 핵심 아이디어는 관리되는 클래스가 DI컨테이너에 의존성이 없어야 한다. 즉, 필요한 의존성을 전달하면 독립적으로 인스턴스화 할 수 있는 단순 POJO여야 한다. DI컨테이너 없이도 유닛테스트에서 인스턴스화 시킬 수 있고, 각각 나누어서 테스트도 할 수있다. 컨테이너의 결합성이 없다면 관리하거나 관리하지 않는 클래스를 사용할 수있고, 심지어 다른 DI컨테이너로 전환 할 수있다. 

 

 

불변성(Immutability)
Constructor Injection과 다르게 Field Injection은 final을 선언할 수 없다. 그래서 객체가 변할 수 있다.

순환 의존성
Constructor Injection에서 순환 의존성을 가질 경우 BeanCurrentlyCreationExeption을 발생시킴으로써 순환 의존성을 알 수 있다.

  • 순환 의존성이란? First Class가 Second Class를 참조하는데 Second Class가 다시 First Class를 참조할 경우 혹은 First Class가 Second Class를 참조하고, Second Class가 Third Class를 참조하고 Third Class가 First Class를 참조하는 경우 이를 순환 의존성이라고 부른다.

 

그럼 Setter Injection 과 Constructor Injection중에서는 어떤걸 추천할까?

 

Setter injection

Setter Injection은 선택적인 의존성을 사용할 때 유용하다. 상황에 따라 의존성 주입이 가능하다. 스프링 3.x버전에서는 Setter Injection을 추천했었다.

 

Constructor Injection

Constructor Injection은 필수적인 의존성 주입에 유용하다. 그리고 final을 선언 할 수 있으므로 객체가 불변 하도록 할 수있다. 그리고 순환 의존성 여부도 파악할수 있다. 그래서 이 코드가 나쁜 디자인 패턴이여서 리팩토링 해야하는지 아닌지 여부도 판단이 가능하다.

 

스프링 4.3버전 부터는 클래스를 DI프레임워크로부터 분리할 수있다. 단일 생성자에 한해 @Autowired를 붙이지 않아도 된다. 이러한 장점 때문에 스프링 4.x버전서는 Setter Injection이아닌 Constructor Injection을 권장한다. 

 

굳이 Setter Injection을 사용한다면, 합리적인 디폴트를 부여 할 수있고 선택적인 의존성을 사용할 때만 사용해야한다고 말한다.

그렇지 않으면 not-null체크 의존성을 사용하는 모든 코드에 구현해야한다.

 

 

 

출처:https://zorba91.tistory.com/238

+ Recent posts