의존성 주입 컨테이너의 이점은 무엇입니까?


104

의존성 주입 자체의 이점을 이해합니다. 예를 들어 Spring을 보자. 또한 AOP, 다른 종류의 도우미 등과 같은 다른 Spring 기능의 이점을 이해합니다. 다음과 같은 XML 구성의 이점이 무엇인지 궁금합니다.

<bean id="Mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="John" class="foo.bar.Male">
  <property name="girlfriend" ref="Mary"/>
</bean>

다음과 같은 일반 오래된 자바 코드와 비교 :

Female mary = new Female();
mary.setAge(23);
Male john = new Male();
john.setGirlfriend(mary);

디버깅이 더 쉽고 컴파일 시간이 확인되며 java 만 아는 사람이라면 누구나 이해할 수 있습니다. 그렇다면 의존성 주입 프레임 워크의 주요 목적은 무엇일까요? (또는 그 이점을 보여주는 코드입니다.)


UPDATE :
의에서 케이스

IService myService;// ...
public void doSomething() {  
  myService.fetchData();
}

IoC 프레임 워크가 둘 이상의 myService 구현을 주입 할 것인지 추측 할 수 있습니까? 주어진 인터페이스의 구현이 하나 뿐이고 IoC 컨테이너가 자동으로이를 사용하도록 결정하면 두 번째 구현이 나타난 후 중단됩니다. 그리고 의도적으로 인터페이스의 가능한 구현이 하나만있는 경우이를 삽입 할 필요가 없습니다.

IoC의 이점을 보여주는 작은 구성을 보는 것은 정말 흥미로울 것입니다. 나는 한동안 Spring을 사용 해왔고 그러한 예를 제공 할 수 없다. 그리고 내가 사용하는 최대 절전 모드, dwr 및 기타 프레임 워크의 이점을 보여주는 단일 행을 표시 할 수 있습니다.


업데이트 2 :
IoC 구성을 다시 컴파일하지 않고도 변경할 수 있음을 알고 있습니다. 정말 좋은 생각인가요? 누군가가 재 컴파일하지 않고 DB 자격 증명을 변경하려는 경우 이해할 수 있습니다. 개발자가 아닐 수도 있습니다. 실제로 개발자가 아닌 다른 사람이 IoC 구성을 얼마나 자주 변경합니까? 개발자에게는 구성을 변경하는 대신 특정 클래스를 다시 컴파일하려는 노력이 없다고 생각합니다. 그리고 개발자가 아닌 경우에는 그의 삶을 더 쉽게 만들고 더 간단한 구성 파일을 제공하고 싶을 것입니다.


업데이트 3 :

인터페이스와 구체적인 구현 간의 매핑에 대한 외부 구성

그것을 확장하는 데 무엇이 그렇게 좋은가요? 모든 코드를 외부로 만들지는 않지만, 확실히 할 수 있습니다. ClassName.java.txt 파일에 넣고 즉시 수동으로 읽고 컴파일합니다. 와우, 재 컴파일을 피했습니다. 왜 컴파일을 피해야합니까?!

절차 코드가 아닌 선언적으로 매핑을 제공하므로 코딩 시간이 절약됩니다.

때때로 선언적 접근 방식이 시간을 절약한다는 것을 이해합니다. 예를 들어 빈 속성과 DB 열 사이의 매핑을 한 번만 선언하고 최대 절전 모드에서는 HSQL을 기반으로 SQL을로드, 저장, 빌드하는 동안이 매핑을 사용합니다. 여기서 선언적 접근 방식이 작동합니다. Spring의 경우 (제 예에서) 선언에는 더 많은 줄이 있고 해당 코드와 동일한 표현력을 가졌습니다. 이러한 선언이 코드보다 짧은 예가 있다면보고 싶습니다.

Inversion of Control 원칙을 사용하면 실제 구현을 가짜 구현으로 대체 할 수 있기 때문에 쉽게 단위 테스트가 가능합니다 (예 : SQL 데이터베이스를 메모리 내 구현으로 대체).

제어의 역전 이점을 이해합니다 (여기서 논의한 디자인 패턴을 종속성 주입이라고 부르는 것을 선호합니다. 왜냐하면 IoC가 더 일반적이기 때문입니다-많은 종류의 제어가 있고 그중 하나만 반전하고 있습니다-초기화 제어). 나는 왜 누군가가 그것을 위해 프로그래밍 언어가 아닌 다른 것을 필요로하는지 물었다. 코드를 사용하여 실제 구현을 가짜 구현으로 대체 할 수 있습니다. 그리고이 코드는 구성과 동일한 것을 표현합니다. 단지 가짜 값으로 필드를 초기화합니다.

mary = new FakeFemale();

DI의 이점을 이해합니다. 동일한 작업을 수행하는 코드를 구성하는 것과 비교하여 외부 XML 구성에 의해 추가되는 이점을 이해하지 못합니다. 나는 컴파일을 피해야한다고 생각하지 않는다. 나는 매일 컴파일하고 여전히 살아있다. DI의 구성은 선언적 접근의 나쁜 예라고 생각합니다. 선언은 한 번 선언하고 다른 방식으로 여러 번 사용하면 유용 할 수 있습니다.-hibernate cfg와 같이 빈 속성과 DB 컬럼 간의 매핑이 검색 쿼리 저장,로드, 빌드 등에 사용됩니다. Spring DI 구성은 쉽게 번역 할 수 있습니다. 이 질문의 시작 부분과 같이 코드를 구성 할 수 있습니까? 그리고 빈 초기화를 위해서만 사용되는 것 아닌가요? 이것은 선언적 접근 방식이 여기에 아무것도 추가하지 않는다는 것을 의미합니까?

hibernate mapping을 선언 할 때, hibernate에 몇 가지 정보를 제공하고이를 기반으로 작동합니다. 무엇을해야하는지 알려주지 않습니다. 봄의 경우, 내 선언은 봄에 정확히 무엇을해야하는지 알려줍니다. 왜 그것을 선언하고, 왜 그렇게하지 않습니까?


마지막 업데이트 :
여러분, 많은 답변이 의존성 주입에 대해 말해주고 있습니다. 문제는 코드를 초기화하는 대신 DI 구성의 목적에 관한 것입니다. 코드 초기화가 더 짧고 명확하다고 생각하는 경향이 있습니다. 지금까지 내 질문에 대한 유일한 대답은 구성이 변경 될 때 재 컴파일을 피한다는 것입니다. 나는 다른 질문을 게시해야한다고 생각한다. 그것은 나에게 큰 비밀이기 때문에 왜이 경우 컴파일을 피해야 하는가.


21
마침내 누군가이 질문을 할 용기가 생겼습니다. 도구 / IDE 지원을 희생 (또는 최소한 저하시키는) 비용으로 구현이 변경 될 때 실제로 재 컴파일을 피하고 싶은 이유는 무엇입니까?
Christian Klauser 2010-08-31

3
제목이 옳지 않은 것 같습니다. 저자는 IOC 컨테이너는 괜찮지 만 코드를 통해 구성하는 대신 XML 구성을 사용하는 데 문제가있는 것 같습니다 (그리고 충분히 공정함). "XML 또는 기타 비 코드 접근 방식을 통해 IOC 컨테이너를 구성하면 어떤 이점이 있습니까?"라고 제안합니다.
Orion Edwards

내가 제공 한 @Orion 예제 (남성 및 여성 포함)에는 IOC 컨테이너가 필요하지 않습니다. IOC는 괜찮습니다. XML을 사용하여 구성했는지 여부에 관계없이 컨테이너를 사용하는 것은 여전히 ​​나에게 열린 질문입니다.
Pavel Feldman

@Orion 2 : 대부분의 프로젝트에서 어떤 형태의 IOC를 사용하지만, 그들 중 일부는 변수 할당 컨테이너 또는 If 문 컨테이너의 이점만큼 IOC 컨테이너의 이점을 얻습니다. 언어만으로도 충분합니다. 작업중인 프로젝트를 다시 컴파일하고 개발 / 테스트 / 프로덕션 초기화 코드를 편리하게 분리하는 데 문제가 없습니다. 그래서 저에게는 제목이 좋습니다.
Pavel Feldman

샘플에 문제가 있습니다. 원칙에 것은 주사하고 서비스가 아닌 데이터
제이 섹 Cz에

답변:


40

나 자신을 위해 IoC를 사용하고 외부 구성을 사용하는 주된 이유 중 하나는 다음 두 영역에 있습니다.

  • 테스팅
  • 생산 유지

테스팅

테스트를 3 개의 시나리오로 분할하는 경우 (대규모 개발에서는 매우 일반적 임) :

  1. 단위 테스트
  2. 통합 테스트
  3. 블랙 박스 테스트

마지막 두 테스트 시나리오 (통합 및 블랙 박스)에 대해 수행하려는 작업은 응용 프로그램의 어떤 부분도 다시 컴파일하지 않는 것입니다.

테스트 시나리오에서 구성을 변경해야하는 경우 (예 : 다른 구성 요소를 사용하여 뱅킹 통합을 모방하거나 성능 부하를 수행) 이는 쉽게 처리 할 수 ​​있습니다 (이는 DI 측면을 구성하는 이점이 있습니다. 그래도 IoC.

또한 앱이 여러 사이트 (서버 및 구성 요소 구성이 서로 다름)에서 사용되거나 라이브 환경에서 구성이 변경된 경우 이후 테스트 단계를 사용하여 앱이 이러한 변경 사항을 처리하는지 확인할 수 있습니다.

생산

개발자는 프로덕션 환경 (특히 앱이 여러 고객 또는 별도의 사이트에 배포되는 경우)을 제어 할 수 없으며 (이어서도 안됩니다) IoC 및 외부 구성을 모두 사용하는 것이 나에게 진정한 이점입니다. , 개발자에게 돌아가 테스트를 거치지 않고 라이브 환경을 조정하고 조정하는 것은 인프라 / 프로덕션 지원에 달려 있기 때문입니다 (구성 요소를 이동하는 것뿐이면 비용이 더 많이 듭니다).

요약

IoC의 외부 구성이 다른 (개발자가 아닌)에게 응용 프로그램을 구성 할 수있는 권한을 제공함으로써 얻을 수있는 주요 이점은 내 경험상 제한된 상황에서만 유용합니다.

  • 응용 프로그램은 환경이 다른 여러 사이트 / 클라이언트에 배포됩니다.
  • 프로덕션 환경 및 설정에 대한 제한된 개발 제어 / 입력.
  • 시나리오 테스트.

실제로 나는 환경을 제어 할 수있는 무언가를 개발할 때에도 실행될 것임을 발견했습니다. 시간이 지남에 따라 다른 사람에게 구성을 변경할 수있는 기능을 제공하는 것이 더 좋습니다.

  • 개발할 때 언제 변경 될지 알 수 없습니다 (앱이 너무 유용해서 회사에서 다른 사람에게 판매합니다).
  • 좋은 구성 모델을 설정하고 사용하여 처리 할 수있는 약간의 변경이 요청 될 때마다 코드를 변경하는 데 집착하고 싶지 않습니다.

참고 : 응용 프로그램은 실행 파일뿐 아니라 전체 솔루션을 참조하므로 응용 프로그램을 실행하는 데 필요한 모든 파일이 있습니다 .


14

의존성 주입은 객체 위임이 일반적으로 객체 상속보다 더 유용한 디자인 패턴이라는 관찰에 뿌리를 둔 코딩 스타일입니다 (즉, 객체가있는 관계가 객체가있는 관계보다 더 유용합니다). 그러나 DI가 작동하려면 객체 인터페이스를 만드는 다른 요소가 필요합니다. 이 두 가지 강력한 디자인 패턴을 결합한 소프트웨어 엔지니어는 유연하게 느슨하게 결합 된 코드를 생성 할 수 있다는 것을 빠르게 깨달았고 따라서 종속성 주입 개념이 탄생했습니다. 그러나 DI가 실제로 시작된 것은 특정 고급 언어에서 객체 반사를 사용할 수있게되기 전까지는 아니 었습니다. 반사 구성 요소는 오늘날 대부분의 핵심입니다.

언어는 일반적인 객체 지향 프로그래밍 기술과 객체 인터페이스 및 객체 리플렉션 (예 : Java 및 C #)에 대한 지원을 모두 제공해야합니다. C ++ 시스템에서 DI 패턴을 사용하여 프로그램을 빌드 할 수 있지만 적절한 언어 내에서 리플렉션 지원이 부족하여 애플리케이션 서버 및 기타 DI 플랫폼을 지원하지 못하므로 DI 패턴의 표현성이 제한됩니다.

DI 패턴을 사용하여 구축 된 시스템의 강점 :

  1. DI 코드는 '종속'기능이 잘 정의 된 인터페이스로 외삽되기 때문에 재사용이 훨씬 더 쉬워서 적절한 애플리케이션 플랫폼에서 구성을 처리하는 별도의 객체를 마음대로 다른 객체에 연결할 수 있습니다.
  2. DI 코드는 테스트하기가 훨씬 쉽습니다. 객체가 표현하는 기능은 애플리케이션 로직에서 기대하는 인터페이스를 구현하는 '모의'객체를 빌드하여 블랙 박스에서 테스트 할 수 있습니다.
  3. DI 코드가 더 유연합니다. 그것은 본질적으로 느슨하게 결합 된 코드입니다. 이를 통해 프로그래머는 한쪽 끝에서 필요한 인터페이스와 다른 쪽 끝에서 표현 된 인터페이스를 기반으로 객체가 연결되는 방식을 선택하고 선택할 수 있습니다.
  4. DI 개체의 외부 (Xml) 구성은 다른 사람들이 예상치 못한 방향으로 코드를 사용자 지정할 수 있음을 의미합니다.
  5. 외부 구성은 또한 객체 초기화 및 객체 상호 의존성 관리의 모든 문제를 애플리케이션 서버에서 처리 할 수 ​​있다는 점에서 관심 패턴의 분리입니다.
  6. DI 패턴을 사용하기 위해 외부 구성이 필요하지 않습니다. 단순한 상호 연결의 경우 작은 빌더 개체가 종종 적합합니다. 둘 사이의 유연성에는 절충안이 있습니다. 빌더 개체는 외부에서 볼 수있는 구성 파일만큼 유연하지 않습니다. DI 시스템 개발자는 구성 파일에 표현 된 개체 구성에 대한 소규모의 미세한 입자 제어가 혼란과 유지 관리 비용을 증가시킬 수 있다는 점에주의하면서 편의성보다 유연성의 장점을 평가해야합니다.

확실히 DI 코드는 더 복잡해 보이지만, 객체가 다른 객체에 주입되도록 구성하는 모든 XML 파일을 갖는 단점은 어려워 보입니다. 그러나 이것이 DI 시스템의 핵심입니다. 일련의 구성 설정으로 코드 개체를 혼합하고 일치시키는 기능을 사용하면 최소한의 코딩으로 타사 코드를 사용하여 복잡한 시스템을 구축 할 수 있습니다.

질문에 제공된 예제는 적절하게 팩터링 된 DI 개체 라이브러리가 제공 할 수있는 표현력의 표면에 대해서만 다룹니다. 약간의 연습과 많은 자기 훈련을 통해 대부분의 DI 실무자들은 애플리케이션 코드의 100 % 테스트 범위를 갖는 시스템을 구축 할 수 있다는 것을 알게됩니다. 이 원 포인트만으로는 대단합니다. 이것은 수백 줄의 코드로 이루어진 소규모 애플리케이션의 100 % 테스트 범위가 아니라 수십만 줄의 코드로 구성된 애플리케이션의 100 % 테스트 범위입니다. 이 수준의 테스트 가능성을 제공하는 다른 디자인 패턴을 설명 할 수 없습니다.

단 10 줄의 코드를 적용하는 것이 여러 객체와 일련의 XML 구성 파일보다 이해하기 쉽다는 점에서 맞습니다. 그러나 가장 강력한 디자인 패턴과 마찬가지로 시스템에 새로운 기능을 계속 추가하면 이점을 얻을 수 있습니다.

요컨대 대규모 DI 기반 애플리케이션은 디버그하기 쉽고 이해하기 쉽습니다. Xml 구성은 '컴파일 시간 검사'가 아니지만이 작성자가 알고있는 모든 응용 프로그램 서비스는 호환되지 않는 인터페이스를 가진 개체를 다른 개체에 삽입하려고하면 개발자에게 오류 메시지를 제공합니다. 그리고 대부분은 알려진 모든 개체 구성을 다루는 '확인'기능을 제공합니다. 이는 주입 될 개체 A가 구성된 모든 개체 주입에 대해 개체 B에 필요한 인터페이스를 구현하는지 확인하여 쉽고 빠르게 수행됩니다.


4
DI의 이점을 이해합니다. 동일한 기능을 수행하는 코드를 구성하는 것과 비교하여 외부 XML 구성에 의해 추가되는 이점을 이해하지 못합니다. 언급 한 이점은 DI 디자인 패턴에서 제공합니다. 질문은 일반 초기화 코드에 비해 DI 구성의 이점에 관한 것이 었습니다.
Pavel Feldman

> 외부 구성도 분리입니다. 구성 분리가 좋은 DI의 핵심입니다. 그리고 초기화 코드를 사용하여 돔을 만들 수 있습니다. 코드 초기화에 비해 cfg가 추가하는 것은 무엇입니까? 나를 위해 cfg의 각 줄에는 해당 초기화 코드 줄이있는 것 같습니다.
Pavel Feldman

7

이것은 약간의로드 된 질문이지만, 엄청난 양의 xml 구성이 실제로 많은 이점을 얻지 못한다는 데 동의하는 경향이 있습니다. 나는 내 애플리케이션이 무거운 프레임 워크를 포함하여 가능한 한 종속성에 대해 가벼워지는 것을 좋아합니다.

그들은 코드를 많이 단순화하지만 문제를 추적하는 것을 다소 어렵게 만드는 복잡성에 오버 헤드가 있습니다 (나는 이러한 문제를 직접 본 적이 있으며 곧바로 Java를 처리하는 것이 훨씬 더 편안 할 것입니다).

스타일에 따라 조금씩 다르고, 어떤 것에 익숙한 지 ... 자신 만의 솔루션을 사용하고 내부를 아는 이점이 있습니까? 아니면 구성이 어려울 때 어려울 수있는 기존 솔루션을 활용하는 것을 좋아합니까? 옳지? 모두 절충안입니다.

그러나 XML 구성은 제 생각에 약간의 관심을 불러 일으키는 부분입니다. 저는 어떤 대가를 치르더라도이를 피하려고합니다.


5

코드를 데이터로 변경할 수있을 때마다 올바른 방향으로 나아가고 있습니다.

무엇이든 데이터로 코딩한다는 것은 코드 자체가 더 일반적이고 재사용 가능하다는 것을 의미합니다. 또한 데이터가 정확히 맞는 언어로 지정 될 수 있음을 의미합니다.

또한 XML 파일을 GUI 또는 기타 도구로 읽어서 실용적으로 쉽게 조작 할 수 있습니다. 코드 예제로 어떻게 하시겠습니까?

저는 대부분의 사람들이 코드로 구현하는 것을 데이터에 지속적으로 고려하고 있습니다. 그러면 코드가 훨씬 더 깔끔해집니다. 사람들이 데이터가 아닌 코드로 메뉴를 생성한다는 것은 상상할 수없는 일입니다. 코드에서 메뉴를 만드는 것은 상용구 때문에 명백히 잘못된 것입니다.


이 관점에서 생각하지 않았습니다
Pavel Feldman

7
다시 말하지만, 사람들은 종종 다른 방식으로 데이터에 논리를 입력하려고 시도합니다. 이는 결국 응용 프로그램을 표준 이하의 프로그래밍 언어로 코딩하는 것을 의미합니다
Casebash

@Casebash 흥미로운 관점입니다. 저는 놀랍게도 한 예에 관심이있을 것입니다. 데이터로 이동할 수있는 모든 것이 도움이됩니다. 또한 말씀하신대로한다면 DSL이기 때문에 언어가 실제로 향상되지만 완전히 새로운 언어를 만드는 데에는 심각한 정당성이 필요하다는 것을 알게되었습니다.
Bill K

1
"언제든지 코드를 데이터로 변경할 수 있으며 올바른 방향으로 한 걸음 내딛고 있습니다." 소프트 코딩 안티 패턴에 오신 것을 환영합니다.
Raedwald 2012

@Raedwald 당신이 말하는 것은 외부화입니다. 당신이 무엇을하는지 모르면 정말 어려울 수 있습니다. , 주석이있는 거의 모든 것, 배열로 초기화되는 모든 것. 대부분의 훌륭한 프로그래밍 구조는 코드의 차이점을 분리하고 남은 것을 결합하여 더 잘 그룹화하고 관리 할 수있는 것으로 유도하려는 시도입니다.
Bill K

3

DI 컨테이너를 사용하는 이유는 단순히 getter 및 setter 인 코드에 수십억 개의 속성을 미리 구성 할 필요가 없기 때문입니다. 정말 new X ()로 모든 것을 하드 코딩 하시겠습니까? 물론 기본값을 가질 수 있지만 DI 컨테이너를 사용하면 싱글 톤을 매우 쉽게 생성 할 수 있으며 코드를 초기화하는 기타 작업이 아니라 코드의 세부 사항에 집중할 수 있습니다.

예를 들어 Spring은 InitializingBean 인터페이스를 구현하고 afterPropertiesSet 메소드를 추가 할 수 있도록합니다 (코드를 Spring에 연결하지 않도록 "init-method"를 지정할 수도 있습니다). 이러한 메서드를 사용하면 클래스 인스턴스의 필드로 지정된 인터페이스가 시작시 올바르게 구성되었는지 확인할 수 있으며 더 이상 getter 및 setter를 null 검사 할 필요가 없습니다 (싱글 톤이 스레드로부터 안전하게 유지되도록 허용한다고 가정). ).

또한 DI 컨테이너를 사용하여 직접 수행하는 대신 복잡한 초기화를 수행하는 것이 훨씬 쉽습니다. 예를 들어 XFire 사용을 지원합니다 (CeltiXFire가 아니라 Java 1.4 만 사용). 이 앱은 Spring을 사용했지만 안타깝게도 XFire의 services.xml 구성 메커니즘을 사용했습니다. 요소 모음이 하나 이상의 인스턴스 대신 0 개 이상의 인스턴스를 가지고 있음을 선언해야 할 때이 특정 서비스에 대해 제공된 XFire 코드 중 일부를 재정의해야했습니다.

Spring Bean 스키마에 정의 된 특정 XFire 기본값이 있습니다. 따라서 Spring을 사용하여 서비스를 구성했다면 Bean을 사용할 수 있습니다. 대신 빈을 사용하는 대신 services.xml 파일에 특정 클래스의 인스턴스를 제공해야했습니다. 이렇게하려면 생성자를 제공하고 XFire 구성에 선언 된 참조를 설정해야했습니다. 내가 변경해야하는 실제 변경은 단일 클래스를 오버로드해야했습니다.

그러나 services.xml 파일 덕분에 4 개의 새 클래스를 생성하여 생성자의 Spring 구성 파일에있는 기본값에 따라 기본값을 설정해야했습니다. Spring 구성을 사용할 수 있었다면 다음과 같이 말할 수 있습니다.

<bean id="base" parent="RootXFireBean">
    <property name="secondProperty" ref="secondBean" />
</bean>

<bean id="secondBean" parent="secondaryXFireBean">
    <property name="firstProperty" ref="thirdBean" />
</bean>

<bean id="thirdBean" parent="thirdXFireBean">
    <property name="secondProperty" ref="myNewBean" />
</bean>

<bean id="myNewBean" class="WowItsActuallyTheCodeThatChanged" />

대신 다음과 같이 보입니다.

public class TheFirstPointlessClass extends SomeXFireClass {
    public TheFirstPointlessClass() {
        setFirstProperty(new TheSecondPointlessClass());
        setSecondProperty(new TheThingThatWasHereBefore());
    }
}

public class TheSecondPointlessClass extends YetAnotherXFireClass {
    public TheSecondPointlessClass() {
        setFirstProperty(TheThirdPointlessClass());
    }
}

public class TheThirdPointlessClass extends GeeAnotherXFireClass {
    public TheThirdPointlessClass() {
        setFirstProperty(new AnotherThingThatWasHereBefore());
        setSecondProperty(new WowItsActuallyTheCodeThatChanged());
    }
}

public class WowItsActuallyTheCodeThatChanged extends TheXFireClassIActuallyCareAbout {
    public WowItsActuallyTheCodeThatChanged() {
    }

    public overrideTheMethod(Object[] arguments) {
        //Do overridden stuff
    }
}

따라서 최종 결과는 하나의 추가 클래스와 몇 가지 간단한 종속성 컨테이너 정보를 달성하는 데 영향을 미치기 위해 코드베이스에 4 개의 추가, 대부분 무의미한 Java 클래스를 추가해야한다는 것입니다. 이것은 "규칙을 증명하는 예외"가 아닙니다. 이것은 규칙입니다. 속성이 DI 컨테이너에 이미 제공되고 특수한 상황에 맞게 속성을 변경하는 경우 코드의 단점 처리가 훨씬 더 깔끔합니다. 더 자주 발생합니다.


3

나는 당신의 대답을 가지고 있습니다

각 접근 방식에는 분명히 상충 관계가 있지만 외부화 된 XML 구성 파일은 IDE가 아닌 빌드 시스템이 코드를 컴파일하는 데 사용되는 엔터프라이즈 개발에 유용합니다. 빌드 시스템을 사용하여 코드에 특정 값을 삽입 할 수 있습니다. 예를 들어 빌드 버전 (컴파일 할 때마다 수동으로 업데이트해야하는 것이 고통 스러울 수 있음). 빌드 시스템이 일부 버전 제어 시스템에서 코드를 가져 오면 고통이 더 커집니다. 컴파일 타임에 간단한 값을 수정하려면 파일을 변경하고 커밋하고 컴파일 한 다음 각 변경 사항에 대해 매번 되돌려 야합니다. 이는 버전 제어에 커밋하려는 변경 사항이 아닙니다.

빌드 시스템 및 외부 구성과 관련된 기타 유용한 사용 사례 :

  • 다른 빌드를위한 단일 코드베이스에 스타일 / 스타일 시트 삽입
  • 단일 코드베이스에 대해 서로 다른 동적 콘텐츠 세트 (또는 이에 대한 참조) 삽입
  • 다른 빌드 / 클라이언트에 대한 현지화 컨텍스트 삽입
  • 웹 서비스 URI를 백업 서버로 변경 (기본 서버가 다운되는 경우)

업데이트 : 위의 모든 예제는 반드시 클래스에 대한 종속성이 필요하지 않은 것에 대한 것입니다. 그러나 복잡한 개체와 자동화가 모두 필요한 경우를 쉽게 구축 할 수 있습니다. 예를 들면 다음과 같습니다.

  • 웹 사이트의 트래픽을 모니터링하는 시스템이 있다고 상상해보십시오. 동시 사용자 수에 따라 로깅 메커니즘을 켜거나 끕니다. 메커니즘이 꺼져있는 동안 스텁 개체가 그 자리에 놓일 수 있습니다.
  • 사용자 수에 따라 참가자 수에 따라 P2P를 수행하는 기능을 전환하려는 웹 회의 시스템이 있다고 가정 해보십시오.

+1은 맨 위에 엔터프라이즈 측면을 강조합니다. 잘못 작성된 레거시 코드를 테스트하는 것은 때때로 며칠 동안의 악몽이 될 수 있습니다.
Richard Le Mesurier

2

구성을 변경할 때마다 코드를 다시 컴파일 할 필요가 없습니다. 프로그램 배포 및 유지 관리를 단순화합니다. 예를 들어 구성 파일을 한 번만 변경하면 한 구성 요소를 다른 구성 요소로 바꿀 수 있습니다.


전개? 아마도 ... 배포 유지 관리? 아마 ... 코드 유지? 나는 안된다고 생각하는 경향이있다. 프레임 워크를 통한 디버깅은 큰 골칫거리 인 경향이 있고, 포조는 그 점에서 다루기가 훨씬 쉽다.
Mike Stone

1
마이크, 나는 코드에 대해 아무 말도하지 않았다. 우리 모두는 XML 구성이 짜증 난다는 것을 알고 있습니다. :)
aku

흠 .. 재 컴파일하지 않고 구성 요소를 얼마나 자주 변경합니까? 누군가 DB 자격 증명을 변경하고 프로그램을 다시 컴파일하고 싶지 않은 경우 이해합니다. 그 사람이이를 개발 한 사람이 아닐 수 있습니다. 하지만 개발자가 아닌 다른 사람이 스프링 구성을 변경하는 것은 거의 상상할 수 없습니다
Pavel Feldman

Pavel은 보통 수백 개의 클라이언트에 프로그램을 배포해야 할 때 발생합니다. 이러한 상황에서는 제품의 새 버전을 배포하는 것보다 구성을 변경하는 것이 훨씬 쉽습니다. 개발자에 대해 말하는 것이 맞습니다. 일반적으로 개발자는 새 cfg를 만들고 관리자가 배포합니다.
aku

2

여자 친구를 위해 새로운 구현을 할 수 있습니다. 따라서 코드를 다시 컴파일하지 않고도 새로운 암컷을 주입 할 수 있습니다.

<bean id="jane" class="foo.bar.HotFemale">
  <property name="age" value="19"/>
</bean>
<bean id="mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="john" class="foo.bar.Male">
  <property name="girlfriend" ref="jane"/>
</bean>

(위는 Female과 HotFemale이 동일한 GirlfFriend 인터페이스를 구현한다고 가정)


재 컴파일하지 않고 논리를 수정하는 것이 좋은 생각 인 이유는 무엇입니까?
Pavel Feldman

나는 확실히 HotFemale jane = new HotFmale (); jane.setAge (19); john.setGirlfriend (jane); 유일한 차이점은 cfg를 다시 컴파일하지 않고 변경할 수 있다는 것입니다. Spring을 논의 할 때 일반적인 대답 인 것 같습니다. 왜?! 컴파일을 피하는 것이 좋은 이유는 무엇입니까?
Pavel Feldman

코드를 더 잘 테스트 할 수 있고 Female Object를 모의 할 수 있습니다.
Paul Whelan

@Pavel Feldman : 이미 클라이언트에 앱을 배포 한 경우 더 쉽습니다.
Andrei Rînea 2010

1

.NET 세계에서 대부분의 IoC 프레임 워크는 XML 및 코드 구성을 모두 제공합니다.

예를 들어 StructureMap과 Ninject는 유창한 인터페이스를 사용하여 컨테이너를 구성합니다. 더 이상 XML 구성 파일을 사용하도록 제한되지 않습니다. .NET에도 존재하는 Spring은 그의 역사적인 기본 구성 인터페이스이기 때문에 XML 파일에 크게 의존하지만, 여전히 프로그래밍 방식으로 컨테이너를 구성 할 수 있습니다.


드디어 사용하고자하는 코드를 사용할 수 있다는 것은 대단한 일입니다. :)하지만 그런 일을하기 위해 프로그래밍 언어 외에 다른 것이 필요한 이유는 무엇입니까?
Pavel Feldman

XML은 프로젝트를 다시 컴파일하지 않고도 런타임 변경 또는 적어도 구성 변경을 허용하기 때문이라고 생각합니다.
Romain Verdier

1

부분 구성 을 최종 전체 구성으로 쉽게 결합 할 수 있습니다.

예를 들어 웹 응용 프로그램에서 모델,보기 및 컨트롤러는 일반적으로 별도의 구성 파일에 지정됩니다. 선언적 접근 방식을 사용하면 다음과 같이로드 할 수 있습니다.

  UI-context.xml
  Model-context.xml
  Controller-context.xml

또는 다른 UI와 몇 가지 추가 컨트롤러로로드합니다.

  AlternateUI-context.xml
  Model-context.xml
  Controller-context.xml
  ControllerAdditions-context.xml

코드에서 동일한 작업을 수행하려면 부분 구성을 결합하기위한 인프라가 필요합니다. 코드에서 불가능하지는 않지만 IoC 프레임 워크를 사용하면 확실히 더 쉽습니다.


1

종종 중요한 점은 프로그램이 작성된 후 구성을 변경하는 사람 입니다. 코드의 구성을 사용하면 변경하는 사람이 원래 작성자와 동일한 기술과 소스 코드 등에 대한 액세스 권한을 가지고 있다고 암시 적으로 가정합니다.

프로덕션 시스템에서는 설정의 일부 하위 집합 (예 : 연령)을 XML 파일로 추출하고 예를 들어 시스템 관리자 또는 지원 담당자가 소스 코드 또는 기타 설정에 대한 전체 권한을 부여하지 않고 값을 변경할 수 있도록 허용하는 것이 매우 실용적입니다. 복잡성에서 분리합니다.


그것은 유효한 점이지만, 스프링 구성은 종종 다소 복잡한 경향이 있습니다. 나이를 변경하는 것은 쉽지만 sysadmin은 완전히 이해할 필요가없는 큰 xml 파일을 처리해야합니다. 스프링 XML 설정보다 더 간단한 것으로 설정해야하는 부분을 추출하는 것이 더 낫지 않습니까? 속성 파일과 마찬가지로 한 줄 "age = 23"이고 관리자가 내부 프로그램 구조에 대한 지식이 필요한 클래스 이름 등과 같은 다른 세부 정보를 변경할 수 없도록합니다.
Pavel Feldman

저는 최근에 Java 코드와 XSLT가 혼합 된 프로젝트를 진행하고있었습니다. 팀은 Java에 능숙한 사람들 (그리고 XML 및 XSLT 작업에 덜 익숙한 사람들)이 혼합되어있었습니다. XML과 XSLT를 매우 강력하게 사용하는 사람들 (Java에 덜 익숙 함). 구성은 두 번째 그룹에서 관리 할 것이기 때문에 Spring을 사용하고 XML 구성을 갖는 것이 합리적이었습니다. 즉, Spring은 팀의 분업 문제를 해결했습니다. 그것은 "기술적"문제를 해결하지 못했습니다. 구성이 Java 코드로 쉽게 수행 될 수 있다는 의미에서.
Dawood ibn Kareem 2011

'지원 담당자'는 종속성 주입 컨테이너 내에서 생성되는 일부 클래스를 변경해야하는 것에 대해 언제 알 수 있습니까 ?? 이 작업을 수행하는 것이 개발자의 일이라는 가정하에 정말로 있습니까?
Jimbo 2013 년

이것이 바로 구성 값 (예 : 통합하는 시스템의 URL)을 추출하는 이유입니다. 지원 담당자가 속성 파일을 편집하거나 (최악의 경우) XML 파일을 편집하면 컴파일 된 Java 클래스가 동일하게 유지됩니다.
Miro A.

1

봄의 관점에서 두 가지 대답을 드릴 수 있습니다.

먼저 XML 구성이 구성을 정의하는 유일한 방법은 아닙니다. 대부분의 작업은 주석을 사용하여 구성 할 수 있으며 XML로 수행해야하는 작업은 라이브러리에서 사용하는 연결 풀과 같이 어쨌든 작성하지 않는 코드에 대한 구성입니다. Spring 3에는 예제의 수동 DI 구성과 유사한 Java를 사용하여 DI 구성을 정의하는 방법이 포함되어 있습니다. 따라서 Spring을 사용한다고해서 XML 기반 구성 파일을 사용해야하는 것은 아닙니다.

두 번째로 Spring은 단순한 DI 프레임 워크 이상입니다. 트랜잭션 관리 및 AOP를 포함한 많은 다른 기능이 있습니다. Spring XML 구성은 이러한 모든 개념을 함께 혼합합니다. 종종 동일한 구성 파일에서 빈 종속성, 트랜잭션 설정을 지정하고 실제로 백그라운드에서 AOP를 사용하여 처리 한 세션 범위 빈을 추가합니다. XML 구성이 이러한 모든 기능을 관리 할 수있는 더 나은 위치를 제공한다는 것을 알았습니다. 또한 주석 기반 구성 및 XML 구성이 Java 기반 구성을 수행하는 것보다 더 잘 확장된다고 생각합니다.

그러나 나는 당신의 요점을 보았고 Java에서 종속성 주입 구성을 정의하는 데 아무런 문제가 없습니다. 일반적으로 단위 테스트에서 직접 수행하고 DI 프레임 워크를 추가하지 않았을 정도로 작은 프로젝트를 작업 할 때합니다. 나는 일반적으로 Java에서 구성을 지정하지 않습니다. Spring을 사용하기로 선택했을 때 작성에서 벗어나려는 종류의 배관 코드이기 때문입니다. 그것은 선호하는 것이지만 XML 구성이 Java 기반 구성보다 우수하다는 것을 의미하지는 않습니다.


0

Spring에는 속성 로더도 있습니다. 이 방법을 사용하여 환경 (예 : 개발, 테스트, 승인, 생산 등)에 의존하는 변수를 설정합니다. 예를 들어 청취 할 대기열이 될 수 있습니다.

속성이 변경되는 이유가없는 경우 이러한 방식으로 구성 할 이유도 없습니다.


0

귀하의 사례는 매우 간단하므로 Spring과 같은 IoC (Inversion of Control) 컨테이너가 필요하지 않습니다. 반면에 "구현이 아닌 인터페이스로 프로그래밍"하면 (OOP에서 좋은 방법 임) 다음과 같은 코드를 가질 수 있습니다.

IService myService;
// ...
public void doSomething() {
  myService.fetchData();
}

(myService의 유형은 구체적인 구현이 아닌 인터페이스 인 IService입니다.) 이제 IoC 컨테이너가 초기화 중에 IService의 정확한 구체적인 인스턴스를 자동으로 제공하도록하는 것이 편리 할 수 ​​있습니다. 인터페이스가 많고 구현이 많은 경우 수동으로 수행하는 것이 번거로울 수 있습니다. IoC 컨테이너 (종속성 주입 프레임 워크)의 주요 이점은 다음과 같습니다.

  • 인터페이스와 구체적인 구현 간의 매핑에 대한 외부 구성
  • IoC 컨테이너는 복잡한 종속성 그래프 해결, 구성 요소 수명 관리 등과 같은 까다로운 문제를 처리합니다.
  • 절차 코드가 아닌 선언적으로 매핑을 제공하므로 코딩 시간이 절약됩니다.
  • Inversion of Control 원칙을 사용하면 실제 구현을 가짜 구현으로 대체 할 수 있기 때문에 쉽게 단위 테스트가 가능합니다 (예 : SQL 데이터베이스를 메모리 내 구현으로 대체).

0

XML 구성 파일에서 초기화하면 컴퓨터에 앱을 배포 한 클라이언트와의 디버깅 / 적응 작업이 단순화됩니다. (재 컴파일 + 바이너리 파일 교체가 필요하지 않기 때문에)


-2

가장 매력적인 이유 중 하나는 " 할리우드 원칙 "입니다. 전화하지 마세요. 전화하겠습니다. 다른 구성 요소 및 서비스 자체에 대한 조회를 수행하는 데 구성 요소가 필요하지 않습니다. 대신 자동으로 제공됩니다. Java에서 이는 더 이상 구성 요소 내부에서 JNDI 조회를 수행 할 필요가 없음을 의미합니다.

구성 요소를 분리하여 단위 테스트하는 것도 훨씬 쉽습니다. 필요한 구성 요소의 실제 구현을 제공하는 대신 간단하게 (자동 생성 된) 모의를 사용합니다.


이 답변은 의존성 주입에 관한 것입니다. 나는 그것이 무엇인지 알고 그것이 좋다는 것을 알고 있으며 질문의 첫 문장에서 그것을 명확하게 진술합니다. 질문은 일반 초기화 코드와 비교하여 DI 구성의 이점에 관한 것이 었습니다.
Pavel Feldman

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