Field Injection이란 정확히 무엇이며 어떻게 피할 수 있습니까?


130

필드 주입 이 권장되지 않는 Spring MVC 및 Portlets에 대한 일부 게시물을 읽었습니다 . 내가 이해하는 것처럼 필드 주입 은 다음과 @Autowired같이 Bean을 주입하는 것입니다.

@Component
public class MyComponent {
    @Autowired
    private Cart cart;
}

내 연구 중에 생성자 주입에 대해서도 읽었습니다 .

@Component
public class MyComponent {
    private final Cart cart;

    @Autowired
    public MyComponent(Cart cart){
       this.cart = cart;
    }
}

이 두 가지 유형의 주사의 장점과 단점은 무엇입니까?


편집 1 : 이 질문의 중복으로 표시되기 때문에 이 질문에 내가 그것을 확인. 질문이나 답변에 코드 예제가 없기 때문에 어떤 주입 유형을 사용하고 있는지 내 추측에 맞다면 명확하지 않습니다.


3
field-injection이 설명하는 것처럼 나쁘다면 Spring은 왜 그것을 허용합니까? 필드 인젝션은 코드를 더 읽기 쉽고 덜 장황하게 만드는 고유 한 이점이 있습니다. 코딩에 충분히 훈련을 받으면 필드 인젝션을 사용해도 문제가 발생하지 않을 것입니다.
ashes

@ashes 당시에는 깔끔한 기능이었고 그 의미가 완전히 생각되지 않았기 때문입니다. Date(int,int,int)존재 하는 동일한 이유 .
chrylis -cautiouslyoptimistic-

답변:


225

주입 유형

종속성을 Bean에 삽입하는 방법에는 세 가지 옵션이 있습니다.

  1. 생성자를 통해
  2. setter 또는 기타 방법을 통해
  3. 반사를 통해 직접 필드로

당신은 옵션 3을 사용하고 있습니다. 그것은 당신이 @Autowired당신의 분야에서 직접 사용할 때 일어나는 일 입니다.


주입 지침

Spring에서 권장 하는 일반 지침 ( Constructor 기반 DI 또는 Setter 기반 DI 섹션 참조 )은 다음과 같습니다.

  • 필수 종속성 또는 불변성을 목표로하는 경우 생성자 주입을 사용하십시오.
  • 선택적 또는 변경 가능한 종속성의 경우 setter 주입을 사용하십시오.
  • 대부분의 경우 필드 주입을 피하십시오

현장 주입 단점

필드 주입이 눈살을 찌푸리는 이유는 다음과 같습니다.

  • 생성자 주입으로 할 수있는 것처럼 불변 객체를 만들 수 없습니다.
  • 클래스는 DI 컨테이너와 긴밀하게 연결되어 있으며 외부에서 사용할 수 없습니다.
  • 리플렉션 없이는 클래스를 인스턴스화 할 수 없습니다 (예 : 단위 테스트). 인스턴스화하려면 DI 컨테이너가 필요하므로 테스트가 통합 테스트와 비슷해집니다.
  • 실제 종속성은 외부에서 숨겨지며 인터페이스 (생성자 또는 메서드)에 반영되지 않습니다.
  • 10 개 정도의 의존성을 갖는 것은 정말 쉽습니다. 생성자 주입을 사용하는 경우 10 개의 인수가 포함 된 생성자가있을 것입니다. 그러나 필드 주입을 사용하여 주입 된 필드를 무기한 추가 할 수 있습니다. 종속성이 너무 많으면 클래스가 일반적으로 하나 이상의 작업을 수행하고 단일 책임 원칙을 위반할 수 있다는 위험 신호입니다.

결론

필요에 따라 주로 생성자 주입을 사용하거나 생성자와 세터 주입을 혼합하여 사용해야합니다. 현장 주입에는 많은 단점이 있으므로 피해야합니다. 필드 주입의 유일한 장점은 모든 단점을 능가하지 않는 쓰기가 더 편리하다는 것입니다.


추가 읽기

필드 주입이 일반적으로 권장되지 않는 이유에 대한 블로그 기사를 작성했습니다. 필드 종속성 주입은 유해한 것으로 간주 됩니다.


12
일반적으로 "현장 주입은 피해야한다"고 세상에 말하는 것은 좋은 생각이 아니고 좋지 않습니다. 장단점과 콘트라를 보여주고 다른 사람이 스스로 결정하게하세요;) 많은 사람들이 다른 경험과 사물을 보는 방식을 가지고 있습니다.
dieter

6
여기에 해당 될 수 있지만 커뮤니티가 무언가를 낙담시키기 위해 일반적인 합의에 도달 한 다른 경우가 있습니다. 예를 들어, 헝가리 표기법을 보겠습니다.
Jannik

테스트 가능성 및 종속성 가시성으로 좋은 점을 주지만 모두 동의하지는 않습니다. 생성자 주입에는 단점이 없습니까? 실제 통화 구성을 수행하는 수업에 5 개 또는 6 개의 필드를 삽입하는 것이 바람직 할 수 있습니다. 불변성에 대해서도 동의하지 않습니다. 최종 필드가 있어야 클래스를 변경할 수없는 것은 아닙니다. 바람직합니다. 그것은 매우 다릅니다.
davidxxx

"을 목표로 할 때 필수 종속성 또는 당신이 의미 생각 불변 "
알렉스 떼로을

1
나는 봄 문서에 링크 대답의 시작 부분에 링크를 참조했다
Vojtech 루지 카

47

이것은 소프트웨어 개발에서 끝없는 논의 중 하나이지만 업계의 주요 영향력있는 사람들은이 주제에 대해 더 많은 의견을 얻고 있으며 더 나은 옵션으로 생성자 주입을 제안하기 시작했습니다.

생성자 주입

장점 :

  • 더 나은 테스트 가능성 . 단위 테스트에서 모의 ​​라이브러리 나 Spring 컨텍스트가 필요하지 않습니다. 키워드 로 테스트 할 개체를 만들 수 있습니다 . 이러한 테스트는 반사 메커니즘에 의존하지 않기 때문에 항상 더 빠릅니다. ( 이 질문 은 30 분 후에 질문 되었습니다. 작성자가 생성자 주입을 사용했다면 나타나지 않았을 것입니다.)
  • 불변성 . 종속성이 설정되면 변경할 수 없습니다.
  • 더 안전한 코드 . 생성자를 실행하면 매개 변수로 전달 된 모든 것을 검증 할 수 있으므로 객체를 사용할 준비가됩니다. 객체는 준비 상태 일 수도 있고 아닐 수도 있으며 중간에 상태가 없습니다. 필드 주입을 사용하면 물체가 깨지기 쉬운 경우 중간 단계를 도입 할 수 있습니다.
  • 필수 종속성의 깔끔한 표현 . 이 문제에서 현장 주입은 모호합니다.
  • 개발자가 디자인에 대해 생각하게합니다 . dit는 8 개의 매개 변수를 가진 생성자에 대해 썼는데, 이것은 실제로 나쁜 디자인의 신호이며 God object anti-pattern 입니다. 클래스의 생성자 또는 필드에 8 개의 종속성이 있는지 여부는 중요하지 않으며 항상 잘못되었습니다. 사람들은 필드를 통하는 것보다 생성자에 더 많은 종속성을 추가하는 것을 더 꺼립니다. 잠시 멈추고 코드 구조에 대해 생각해야한다는 신호로 뇌에 신호를 보냅니다.

단점 :

  • 더 많은 코드 (그러나 최신 IDE는 고통을 덜어줍니다).

기본적으로 필드 주입은 그 반대입니다.


1
테스트 가능성, 예, 필드 주입 콩을 조롱하는 것은 악몽이었습니다. 일단, 나는 contsructor 주입을 사용, 나는 불필요한 조롱을 할 필요가 없다
kenobiwan

25

맛의 문제. 당신의 결정입니다.

하지만 왜 생성자 주입을 사용하지 않는지 설명 할 수 있습니다 .

  1. 모든 @Service, @Repository@Controller콩에 대한 생성자를 구현하고 싶지 않습니다 . 약 40-50 개 이상의 콩이 있습니다. 새 필드를 추가 할 때마다 생성자를 확장해야합니다. 아뇨. 원치 않으며 그럴 필요도 없습니다.

  2. Bean (서비스 또는 컨트롤러)에 많은 다른 Bean을 주입해야하는 경우 어떻게됩니까? 4 개 이상의 매개 변수가있는 생성자는 매우 추합니다.

  3. CDI를 사용하는 경우 생성자가 신경 쓰지 않습니다.


편집 # 1 : Vojtech Ruzicka는 다음과 같이 말했습니다.

클래스에 너무 많은 종속성이 있으며 아마도 단일 책임 원칙을 위반하고 리팩토링되어야합니다.

예. 이론과 현실. 여기에 en 예제가 있습니다 : DashboardControllermapping to single path *:8080/dashboard.

My DashboardController는 다른 서비스에서 많은 정보를 수집하여 대시 보드 / 시스템 개요 페이지에 표시합니다. 이 단일 컨트롤러가 필요합니다. 따라서이 경로 (기본 인증 또는 사용자 역할 필터) 만 보호해야합니다.

편집 # 2 : 모든 사람이 생성자의 8 개 매개 변수에 초점을 맞추고 있기 때문에 ... 이것은 고객의 레거시 코드 인 실제 사례였습니다. 나는 그것을 변경했습니다. 4 개 이상의 매개 변수에 대해 동일한 주장이 나에게 적용됩니다.

인스턴스 생성이 아니라 코드 주입에 관한 것입니다.


34
8 개의 종속성이있는 매우 추악한 생성자는 무언가 잘못되고 클래스가 너무 많은 종속성을 가지고 있으며 아마도 단일 책임 원칙을 위반하고 리팩토링되어야한다는 위험 신호이기 때문에 실제로 훌륭합니다. 실제로 좋은 일입니다.
Vojtech 루지 카

6
@VojtechRuzicka 확실히 좋지는 않지만 때로는 피할 수 없습니다.
다이어트

4
40-50은 말할 것도없고, 3의 규칙은 모든 클래스에 대한 종속성이 리팩토링해야한다는 신호 여야합니다. 40 개의 종속성을 가진 클래스가 단일 책임 주체 또는 열기 / 닫기 주체를 고수 할 수는 없습니다.
Amin J

4
@AminJ 규칙은 훌륭하지만 현실은 다릅니다. 제가 일하고있는 회사는 20 년이 넘었으며 레거시 코드가 많이 있습니다. 리팩토링은 좋은 생각이지만 비용이 많이 듭니다. 또한 나는 왜 말을하는 것을 알고하지 않습니다하지만 난 평균 40 ~ 50 의존성, 나는 40 ~ 50 콩, 구성 요소, 모듈을 의미하지 않았다 ...
다이어트

7
@dit, 당신의 상황은 분명히 기술적 부채로 인해 차선책을 선택하는 상황입니다. 자신의 말에 따르면 의사 결정이 20 년이 넘은 레거시 코드의 영향을 많이받는 상황에 처해 있습니다. 새 프로젝트를 시작할 때 생성자 주입보다 필드 주입을 권장합니까? 어떤 경우에 필드 주입을 선택할 것인지 표시하기 위해 답변에 경고를 넣어야 할 수도 있습니다.
Umar Farooq Khawaja

0

한 가지 더 의견-Vojtech Ruzicka는 Spring이 다음 세 가지 방법으로 빈을 주입한다고 말했습니다 (가장 많은 포인트를 가진 답변).

  1. 생성자를 통해
  2. setter 또는 기타 방법을 통해
  3. 반사를 통해 직접 필드로

이 대답은 잘못되었습니다-모든 종류의 주입 스프링은 반사를 사용하기 때문입니다! IDE를 사용하고 setter / 생성자에 중단 점을 설정하고 확인합니다.

이것은 맛의 문제 일 수 있지만 CASE의 문제 일 수도 있습니다. @dieter는 현장 주입이 더 좋은 경우 훌륭한 사례를 제공했습니다. Spring 컨텍스트를 설정하는 통합 테스트에서 필드 주입을 사용하는 경우-클래스의 테스트 가능성을 가진 인수도 유효하지 않습니다-나중에 테스트에서 통합 테스트에 작성하고 싶지 않은 경우;)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.