[번역] 해로운 것으로 간주되는 필드 종속성 주입

in dependency-injection •  3 years ago 

[번역] https://www.vojtechruzicka.com/field-dependency-injection-considered-harmful/

필드 주입은 Spring과 같은 종속성 주입 프레임워크에서 매우 인기 있는 방법입니다. 그러나 몇 가지 심각한 절충점이 있으므로 일반적으로 피해야 합니다.

주입 유형 종속성을 클래스에 주입하는 세 가지 주요 방법이 있습니다. 생성자, 세터(메소드) 및 필드 주입. 모든 접근 방식에 의해 주입된 동일한 종속성의 코드를 빠르게 비교합시다.

생성자

private DependencyA dependencyA;
private DependencyB dependencyB;
private DependencyC dependencyC;

@Autowired
public DI(DependencyA dependencyA, DependencyB dependencyB, DependencyC dependencyC) {
this.dependencyA = dependencyA;
this.dependencyB = dependencyB;
this.dependencyC = dependencyC;
}

setter

private DependencyA dependencyA;
private DependencyB dependencyB;
private DependencyC dependencyC;

@Autowired
public void setDependencyA(DependencyA dependencyA) {
this.dependencyA = dependencyA;
}

@Autowired
public void setDependencyB(DependencyB dependencyB) {
this.dependencyB = dependencyB;
}

@Autowired
public void setDependencyC(DependencyC dependencyC) {
this.dependencyC = dependencyC;
}

Field

@Autowired
private DependencyA dependencyA;

@Autowired
private DependencyB dependencyB;

@Autowired
private DependencyC dependencyC;

뭐가 잘못 되었 니? 보시다시피 Field 변형은 매우 멋지게 보입니다. 매우 짧고 간결하며 상용구 코드가 없습니다. 코드를 읽고 탐색하기 쉽습니다. 당신의 수업은 중요한 것에 집중할 수 있고 DI 상용구에 의해 오염되지 않습니다. 필드 위에 @Autowired 주석을 넣기만 하면 됩니다. DI 컨테이너가 종속성을 제공하기 위한 특별한 생성자 또는 설정자가 없습니다. Java는 있는 그대로 매우 장황하므로 코드를 더 짧게 만들 수 있는 모든 기회를 환영합니다. 그렇죠?

단일 책임 원칙 위반 새로운 의존성을 추가하는 것은 매우 쉽습니다. 어쩌면 너무 쉽습니다. 6개, 10개 또는 12개의 종속성을 추가하는 데 문제가 없습니다. DI용 생성자를 사용할 때 특정 시점 이후에 생성자 매개변수의 수가 너무 많아지고 무언가 잘못되었다는 것이 즉시 명백해집니다. 종속성이 너무 많다는 것은 일반적으로 클래스에 너무 많은 책임이 있음을 의미합니다. 이는 단일 책임 원칙 및 관심사 분리에 대한 위반일 수 있으며 클래스에 추가 검사 및 가능한 리팩토링이 필요하다는 좋은 지표입니다. 이 접근 방식은 무한정 확장될 수 있으므로 필드에 직접 주입할 때는 이러한 위험 신호가 없습니다.

의존성 은닉 DI 컨테이너를 사용한다는 것은 클래스가 더 이상 자신의 종속성을 관리할 책임이 없다는 것을 의미합니다. 종속성 획득에 대한 책임은 클래스에서 추출됩니다. 이제 다른 사람이 종속성을 제공하거나 테스트에서 수동으로 할당하는 DI 컨테이너를 담당합니다. 클래스가 더 이상 종속성을 획득할 책임이 없으면 공용 인터페이스(메소드 또는 생성자)를 사용하여 명확하게 전달해야 합니다. 이렇게 하면 클래스에 필요한 것이 무엇인지와 선택 사항(설정자)인지 필수 항목(생성자)인지도 명확해집니다.

DI 컨테이너 커플링 DI 프레임워크의 핵심 아이디어 중 하나는 관리되는 클래스가 사용된 DI 컨테이너에 종속되지 않아야 한다는 것입니다. 즉, 필요한 모든 종속성을 전달하는 경우 독립적으로 인스턴스화할 수 있는 일반 POJO여야 합니다. 이렇게 하면 DI 컨테이너를 시작하지 않고 단위 테스트에서 인스턴스화하고 별도로 테스트할 수 있습니다(통합 테스트에 더 가까운 컨테이너 사용). 컨테이너 커플링이 없는 경우 클래스를 관리형 또는 비관리형으로 사용하거나 새 DI 프레임워크로 전환할 수도 있습니다.

그러나 필드에 직접 주입할 때 모든 필수 종속성을 사용하여 클래스를 인스턴스화하는 직접적인 방법을 제공하지 않습니다. 그 의미는:

일부 필수 공동 작업자가 없고 사용 시 NullPointerException이 발생하는 상태에서 new 를 사용하여 객체를 생성하는 방법(기본 생성자를 호출하여)이 있습니다 . 이러한 클래스는 필요한 종속성을 제공하기 위해 리플렉션을 제외하고는 방법이 없기 때문에 DI 컨테이너(테스트, 기타 모듈) 외부에서 재사용할 수 없습니다. 불변성 생성자와 달리 필드 주입은 객체를 변경 가능하게 효과적으로 렌더링하는 최종 필드에 종속성을 할당하는 데 사용할 수 없습니다.

생성자 대 설정자 주입 따라서 Field injection은 올바른 방법이 아닐 수 있습니다. 뭐가 남았어? 설정자와 생성자. 어느 것을 사용해야 합니까?

세터 세터는 선택적 종속성을 주입하는 데 사용해야 합니다. 클래스는 제공되지 않을 때 작동할 수 있어야 합니다. 종속성은 개체가 인스턴스화된 후 언제든지 변경할 수 있습니다. 상황에 따라 이점이 없을 수도 있습니다. 때때로 불변 객체를 갖는 것이 바람직합니다. 때때로 JMX 관리 MBean과 같이 런타임에 객체의 협력자를 변경하는 것이 좋습니다.

Spring 3.x 문서 의 공식 권장 사항은 생성자보다 설정자를 사용하도록 권장합니다.

Spring 팀은 일반적으로 많은 수의 생성자 인수가 다루기 힘들 수 있기 때문에 특히 속성이 선택 사항일 때 setter 주입을 지지합니다. 또한 Setter 메서드는 해당 클래스의 개체를 나중에 재구성하거나 다시 주입할 수 있도록 합니다. JMX MBeans 를 통한 관리 는 매력적인 사용 사례입니다.

일부 순수주의자는 생성자 기반 주입을 선호합니다. 모든 개체 종속성을 제공한다는 것은 개체가 항상 완전히 초기화된 상태에서 클라이언트(호출) 코드로 반환된다는 것을 의미합니다. 단점은 개체가 재구성 및 재주입에 덜 적합하다는 것입니다.

생성자 생성자 주입은 필수 종속성에 좋습니다. 개체가 제대로 작동하는 데 필요한 항목입니다. 생성자에서 제공함으로써 객체가 생성되는 순간 사용할 준비가 되었는지 확인할 수 있습니다. 생성자에 할당된 필드는 최종적일 수도 있으므로 개체가 완전히 변경되지 않거나 최소한 필수 필드를 보호할 수 있습니다.

종속성을 제공하기 위해 생성자를 사용하는 한 가지 결과는 이러한 방식으로 구성된 두 객체 간의 순환 종속성이 더 이상 가능하지 않다는 것입니다(세터 주입과 달리). 순환 종속성을 피해야 하고 일반적으로 잘못된 설계의 신호이기 때문에 이는 실제로 제한이 아니라 좋은 것입니다. 이렇게 하면 그러한 관행이 방지됩니다.

또 다른 장점은 Spring 4.3+를 사용하는 경우 DI 프레임워크에서 클래스를 완전히 분리할 수 있다는 것입니다. 그 이유는 이제 Spring 이 하나의 생성자 시나리오에 대해 암시적 생성자 주입 을 지원하기 때문입니다 . 즉, 더 이상 클래스에 DI 주석이 필요하지 않습니다. 물론 주어진 클래스에 대한 스프링 구성에서 DI를 명시적으로 구성하여 동일한 결과를 얻을 수 있습니다. 이렇게 하면 이 작업이 훨씬 쉬워집니다.

Spring 4.x부터 Spring 문서 변경 및 setter 주입 의 공식 권장 사항은 더 이상 생성자보다 권장되지 않습니다.

Spring 팀은 일반적으로 응용 프로그램 구성 요소를 변경할 수 없는 개체 로 구현 하고 필요한 종속성이 null이 아님을 보장하기 때문에 생성자 주입을 옹호 합니다. 또한 생성자 주입 구성 요소는 항상 완전히 초기화된 상태로 클라이언트(호출) 코드에 반환됩니다. 참고로 많은 수의 생성자 인수는 나쁜 코드 냄새입니다 . 이는 클래스에 너무 많은 책임이 있을 수 있으며 적절한 문제 분리를 더 잘 처리하기 위해 리팩토링해야 함을 의미합니다.

Setter 주입은 주로 클래스 내에서 합리적인 기본값을 할당할 수 있는 선택적 종속성에만 사용해야 합니다. 그렇지 않으면 코드에서 종속성을 사용하는 모든 곳에서 null이 아닌 검사를 수행해야 합니다. setter 주입의 한 가지 이점은 setter 메서드가 해당 클래스의 개체를 나중에 재구성하거나 다시 주입할 수 있도록 만든다는 것입니다.

업데이트: IntelliJ IDEA 지원 이 기사가 게시된 이후로 IDEA는 Field Injection을 감지하고 쉽게 수정하기 위한 몇 가지 유용한 지원을 도입했습니다. @Autowired필드 에서 주석을 자동으로 제거 하고 대신 @Autowired종속성이 있는 생성자를 생성 하여 필드 주입을 생성자 주입으로 효과적으로 대체할 수 있습니다.

IntelliJ IDEA 필드 주입 수정

결론 현장 주입은 대부분 피해야 합니다. 대신에 생성자나 메서드를 사용하여 종속성을 주입해야 합니다. 둘 다 장단점이 있으며 상황에 따라 용도가 다릅니다. 그러나 이러한 접근 방식을 혼합할 수 있으므로 양자택일의 선택이 아니며 하나의 클래스에서 설정자와 생성자 주입을 모두 결합할 수 있습니다. 생성자는 필수 종속성과 불변성을 목표로 할 때 더 적합합니다. 세터는 선택적 종속성에 더 좋습니다.

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!