의존성 주입

Dependency injection
A diagram of an archetypical dependency injection container for the .NET platform.
의존성 주입은 프로그램 구성을 용이하게 하기 위해 '컨테이너'로 알려진 특수 프레임워크와 함께 종종 사용됩니다.

소프트웨어 엔지니어링에서 의존성 주입은 객체 또는 함수가 종속된 다른 객체 또는 함수를 수신하는 설계 패턴입니다.제어의 반전 형태인 의존성 주입은 객체를 구성하고 사용하는 문제를 분리하여 느슨하게 결합된 프로그램을 [1][2][3]유도하는 을 목표로 합니다.이 패턴을 통해 특정 서비스를 사용하려는 개체 또는 함수가 이러한 서비스를 구성하는 방법을 알 필요가 없습니다.대신에, 수신하는 「클라이언트」(객체 또는 함수)는,[4] 의식하지 않는 외부 코드(「인젝터」)에 의해서, 그 의존성을 제공받는다.의존관계 주입은 암묵적인 의존관계를 명확하게 함으로써 도움이 되며 다음 [5]문제를 해결하는 데 도움이 됩니다.

  • 클래스가 종속된 객체의 생성으로부터 독립할 수 있는 방법은 무엇입니까?
  • 응용 프로그램과 응용 프로그램에서 사용하는 개체가 서로 다른 구성을 지원할 수 있는 방법은 무엇입니까?
  • 코드의 동작을 직접 편집하지 않고 변경하려면 어떻게 해야 합니까?

기본적으로 의존성 주입은 매개 변수[6]메서드에 전달하는 것으로 구성됩니다.

클라이언트는 서비스 자체를 구축하거나 검색하지 않기 때문에 일반적으로 사용하는 서비스의 인터페이스를 선언하기만 하면 됩니다.구체적인 실장은 필요 없습니다.이를 통해 런타임에 실제로 사용되는 서비스를 쉽게 변경할 수 있습니다.특히 기본 개체를 변경하면 소스 코드를 다시 컴파일해야 하는 정적 유형의 언어에서는 더욱 그렇습니다.

의존성 주입을 수반하지 않는 제어의 반전 로는 [7]서브클래싱을 통해 다형성을 실현하는 템플릿 방식 패턴이 있다.이와는 대조적으로 의존성 주입은 구성을 통해 제어의 반전을 구현하며 종종 전략 패턴과 유사합니다.차이점은 전략 패턴은 개체의 수명 동안 교환 가능한 종속성을 의도하는 반면 종속성 주입에서는 일반적으로 종속성의 단일 인스턴스만 [8]사용된다는 것입니다.

역할

5세 대상 의존성 주입

여러분이 냉장고에서 직접 물건을 꺼낼 때, 여러분은 문제를 일으킬 수 있습니다.문을 열어두고 엄마나 아빠가 원하지 않는 걸 받을 수도 있어당신은 심지어 우리가 가지고 있지 않거나 유통기한이 지난 것을 찾고 있을지도 모른다.

'점심 때 마실 게 필요해'라고 말하고 앉아서 먹을 때 꼭 챙겨먹도록 하겠습니다.

John Munsch, 28 October 2009.[2][9][10]

의존관계 주입에는 서비스, 클라이언트, 인터페이스 및 인젝터의 4가지 역할이 포함됩니다.

서비스 및 클라이언트

서비스는 유용한 기능을 포함하는 클래스입니다.즉, 클라이언트는 서비스를 사용하는 모든 클래스입니다.

임의의 오브젝트는 서비스 또는 클라이언트가 될 수 있습니다.이러한 이름은 오브젝트가 인젝션에서 수행하는 역할에만 관련됩니다.같은 오브젝트는 클라이언트(인젝트된 서비스를 사용)와 서비스(다른 오브젝트에 삽입됨) 모두일 수도 있습니다.주입 시 서비스는 클라이언트 상태의 일부가 되어 사용할 [11]수 있게 됩니다.

인터페이스

클라이언트는 종속성이 어떻게 구현되는지 알지 못하고 이름과 API만 알아야 합니다.예를 들어 이메일을 보내는 서비스는 백그라운드에서 SMTP 또는 POP3[dubious ] 프로토콜을 사용할 수 있지만 이 세부 사항은 이메일을 보내는 호출 코드와는 무관할 수 있습니다.구현 세부사항을 무시함으로써 클라이언트는 종속성이 변경되었을 때 변경할 필요가 없습니다.

인젝터

인젝터는 어셈블러, 컨테이너, 공급자 또는 팩토리라고도 불리며 클라이언트에 서비스를 도입합니다.

인젝터의 역할은 복잡한 객체 그래프를 구성하고 연결하는 것입니다. 여기서 객체는 클라이언트와 서비스일 수 있습니다.인젝터 자체는 함께 작동하는 여러 개체일 수 있지만 순환 종속성이 생성되므로 클라이언트일 수는 없습니다.

의존성 주입은 오브젝트가 어떻게 구성되는지와 오브젝트가 어떻게 사용되는지를 분리하기 때문에 대부분의 오브젝트 지향 언어에서 볼 수 있는 키워드의 중요성을 떨어뜨리는 경우가 많습니다.프레임워크가 서비스 생성을 처리하기 때문에 프로그래머는 프로그램 도메인(예: 프로그램 도메인)에서 엔티티를 나타내는 가치 객체만 직접 구성하는 경향이 있습니다.Employee비즈니스 어플리케이션 또는 비즈니스 어플리케이션에서 오브젝트Order오브젝트)[12][13][14][15]를 표시합니다.

유추

유추하자면, 자동차는 사람들을 한 곳에서 다른 곳으로 운반하는 유용한 작업을 수행하는 서비스라고 생각할 수 있다.자동차 엔진에는 가스, 디젤 또는 전기가 필요할 수 있지만, 목적지에 도달할 수 있는지 여부만 신경 쓰는 운전자에게는 이러한 세부 사항은 중요하지 않습니다.

자동차는 페달, 스티어링 휠 및 기타 컨트롤을 통해 균일한 인터페이스를 제공합니다.따라서 공장 라인에서 어떤 엔진을 '인젝트'했는지는 더 이상 중요하지 않으며, 운전자는 필요에 따라 어떤 종류의 자동차든 전환할 수 있습니다.

장점과 단점

이점

의존성 주입의 기본적인 이점은 클래스 및 그 의존성 [16][17]간의 결합 감소입니다.

의존관계가 구현되는 방법에 대한 클라이언트의 지식을 제거함으로써 프로그램의 재사용, 테스트 및 [18]유지보수가 용이해집니다.

이것에 의해, 유연성이 향상됩니다.클라이언트는 클라이언트가 [19]기대하는 고유의 인터페이스를 서포트하는 모든 것에 대응합니다.

보다 일반적으로 의존성 주입은 모든 의존성 생성이 단일 [18]컴포넌트에 의해 처리되기 때문에 보일러 플레이트 코드를 줄입니다.

마지막으로 의존성 주입은 동시 개발을 가능하게 합니다.두 개발자가 서로 사용하는 클래스를 독립적으로 개발할 수 있지만 클래스가 통신하는 인터페이스를 알면 됩니다.플러그인은 대부분의 경우 원래 제품의 [20]개발자와 대화조차 하지 않는 서드파티에 의해 개발됩니다.

테스트

의존성 주입의 많은 편익은 특히 단위 테스트와 관련이 있다.

예를 들어 의존성 주입을 사용하여 시스템의 구성 세부 정보를 구성 파일로 외부화할 수 있으므로 시스템을 다시 컴파일하지 않고 재구성할 수 있습니다.컴포넌트의 [21]실장이 다른 상황에 따라 다른 설정을 작성할 수 있습니다.

마찬가지로 종속성 주입은 코드 동작을 변경할 필요가 없으므로 리팩터링으로 레거시 코드에 적용할 수 있습니다.이로 인해 클라이언트의 독립성이 향상되고 테스트 대상이 아닌 다른 오브젝트를 시뮬레이트하는 스터브 또는 모의 오브젝트를 사용하여 분리하여 테스트하는 것이 쉬워집니다.

이러한 테스트의 용이성은 의존성 [22]주입을 사용할 때 가장 먼저 눈에 띄는 이점입니다.

단점들

의존성 주입을 비판하는 사람들은 다음과 같이 주장한다.

  • 설정 상세 정보를 요구하는 클라이언트를 만듭니다.이는 명백한 기본값을 사용할 [20]수 있는 경우 부담이 될 수 있습니다.
  • 동작과 [20]구성을 분리하기 때문에 코드를 추적하기가 어렵습니다.
  • 일반적으로 리플렉션 또는 동적 프로그래밍과 함께 구현되어 IDE [23]자동화를 방해합니다.
  • 일반적으로 선행 개발 작업이 [24]더 필요합니다.
  • 프레임워크에 [25][26][27]대한 의존도를 높입니다.

종속성 주입 유형

클라이언트가 주입된 [28]서비스를 받을 수 있는 방법은 크게 세 가지가 있습니다.

  • 생성자 주입 - 클라이언트의 클래스 생성자를 통해 종속성이 제공됩니다.
  • 세터 주입: 클라이언트가 종속성을 받아들이는 세터 메서드를 노출합니다.
  • 인터페이스 주입. 종속성의 인터페이스는 전달된 클라이언트에 종속성을 주입하는 인젝터 메서드를 제공합니다.

일부 프레임워크에서는 클라이언트가 종속성 주입을 적극적으로 수락할 필요가 전혀 없습니다.예를 들어 Java에서는 리플렉션을 통해 서비스를 직접 [29]테스트하고 주입할 때 개인 속성을 공개할 수 있습니다.

의존성 주입 없음

다음 Java 예제에서는Client클래스에 포함되다Service 생성자에서 초기화된 멤버 변수입니다.클라이언트는 사용하는 서비스를 직접 구성하고 제어하여 하드 코드화된 종속성을 생성합니다.

일반의 학급 고객 {          사적인 서비스 예시 서비스;      고객() {         서비스 = 신규 서비스 예시();     } } 

생성자 주입

종속성 주입의 가장 일반적인 형식은 클래스가 생성자를 통해 종속성을 요청하는 것입니다.이것에 의해, 클라이언트는 필요한 의존 관계 없이 인스턴스화할 수 없기 때문에, 항상 유효한 상태가 됩니다.

// 이 클래스는 생성자에서 서비스를 받아들입니다. 고객(서비스 서비스) {          // 클라이언트는 구축을 허용하기 전에 종속성이 유효한지 확인할 수 있습니다.     한다면 (서비스 == 무효) {         던지다 신규 유효하지 않은 파라미터예외.("서비스는 null일 수 없습니다.");     }      // 클라이언트는 일반적으로 참조를 저장하여 클래스의 다른 메서드가 참조에 액세스할 수 있도록 합니다.     이것..서비스 = 서비스; } 

세터 주입

클라이언트는 생성자가 아닌 세터 방법을 통해 종속성을 수용함으로써 인젝터가 언제든지 종속성을 조작할 수 있도록 할 수 있습니다.

이로 인해 유연성은 확보되지만 클라이언트를 사용하기 전에 모든 의존관계가 주입되고 유효하게 되는 것은 어렵습니다.

// 이 클래스는 종속성을 받아들이는 메서드를 제공합니다. 일반의 무효 set 서비스(서비스 서비스) {     이것..서비스 = 서비스; }  // 클라이언트는 즉시 또는 다른 방법으로 종속성을 검증할 수 있습니다. 사적인 무효 validate State() {     한다면 (서비스 == 무효) {         던지다 신규 Illogal State Exception(불법 상태 예외)("서비스는 null일 수 없습니다.");     } }  // 서비스가 유효한지 확인한 후 사용하는 메서드 일반의 무효 어떻게 좀 해봐.() {     validate State();     서비스.당신의 일을 하라.(); } 

인터페이스 주입

인터페이스 주입을 사용하면 의존관계는 클라이언트에 대해 전혀 알지 못하지만 새로운 클라이언트에 대한 참조를 송수신합니다.

이렇게 하면 의존성이 인젝터가 됩니다.중요한 것은 주입 방식이 인터페이스를 통해 제공된다는 것입니다.

클라이언트와 그 의존관계를 도입하기 위해서는 어셈블러가 여전히 필요합니다.어셈블러는 클라이언트에 대한 참조를 취득하여 그 의존관계를 설정하는 세터인터페이스에 캐스트하고 의존관계 오브젝트에 전달합니다. 의존관계 오브젝트는 다시 클라이언트에 참조를 전달합니다.

인터페이스 주입에 가치를 부여하려면 종속성이 단순히 참조를 자신에게 전달하는 것 외에 다른 작업을 수행해야 합니다.이는 다른 종속성을 해결하기 위한 공장 또는 하위 어셈블러 역할을 할 수 있으며, 따라서 메인 어셈블러에서 일부 세부 정보를 추상화할 수 있습니다.이는 참조 카운팅일 수 있으므로 종속성이 이를 사용하는 클라이언트 수를 알 수 있습니다.종속성이 클라이언트의 컬렉션을 유지하는 경우 나중에 클라이언트에 다른 인스턴스를 주입할 수 있습니다.

// 서비스 세터인터페이스 일반의 인터페이스 서비스 세터 {     일반의 무효 set 서비스(서비스 서비스); }  // 클라이언트클래스 일반의 학급 고객 용구 서비스 세터 {     // 이 클라이언트에서 사용하는 서비스에 대한 내부 참조입니다.     사적인 서비스 서비스;      // 이 클라이언트가 사용할 서비스를 설정합니다.     @오버라이드     일반의 무효 set 서비스(서비스 서비스) {         이것..서비스 = 서비스;     } }  // 인젝터 클래스 일반의 학급 서비스 인젝터 {  세트< >서비스 세터> 클라이언트;  일반의 무효 주입하다(서비스 세터 고객) {   클라이언트.더하다(고객);   고객.set 서비스(신규 서비스 FOO());  }  일반의 무효 스위치토바() {   위해서 (고객 고객 : 클라이언트) {    고객.set 서비스(신규 서비스 바());   }  } }  // 서비스 클래스 일반의 학급 서비스 FOO 용구 서비스 {} 일반의 학급 서비스 바 용구 서비스 {} 

어셈블리

의존성 주입을 구현하는 가장 간단한 방법은 일반적으로 실행이 시작되는 프로그램의 'root'에서 이루어지는 서비스와 클라이언트를 수동으로 배열하는 것입니다.

일반의 학급 프로그램. {     일반의 정적인 무효 주된(스트링[] args) {         // 서비스 구축         서비스 서비스 = 신규 서비스 예시();          // 서비스를 클라이언트에 주입합니다.         고객 고객 = 신규 고객(서비스);          // 객체 사용         시스템..나가..인쇄(고객.환영하다());     }  } 

수동 시공은 더 복잡할 수 있으며 건설업자, 공장 또는 기타 건설 패턴을 수반합니다.

프레임워크

A class diagram of dependency injection containers in the .NET Framework.
Ninject 또는 StructureMap과 같은 컨테이너는 일반적으로 객체 지향 프로그래밍 언어에서 제어의 반전을 달성하기 위해 사용됩니다.

대규모 프로젝트에서는 수동 의존성 주입이 지루하고 오류가 발생하기 쉬운 경우가 많기 때문에 프로세스를 자동화하는 프레임워크 사용이 촉진됩니다.수동 의존성 주입은 구성 코드가 애플리케이션에 더 이상 커스텀되지 않고 대신 [30]범용적인 종속성 주입 프레임워크가 됩니다.이러한 도구는 유용하지만 종속성 [31][32]주입에 필요하지 않습니다.

Spring과 같은 일부 프레임워크에서는 외부 구성 파일을 사용하여 프로그램 구성을 계획할 수 있습니다.

수입품 org. springframework.콩류.빈팩토리; 수입품 org.springframework.springfrack응용 프로그램 컨텍스트; 수입품 org.springframework.springfrack지지하다.ClassPathXml Application Context;  일반의 학급 분사기 {  일반의 정적인 무효 주된(스트링[] args) {   // 사용할 구체적인 서비스에 대한 자세한 내용은 프로그램 자체와 별도로 구성에 저장됩니다.   빈팩토리 콩 공장 = 신규 ClassPathXml Application Context("Beans.xml");      고객 고객 = (고객) 콩 공장.getBean("클라이언트");    시스템..나가..인쇄(고객.환영하다());  } } 

잠재적으로 길고 복잡한 객체 그래프를 사용하더라도 코드에서 언급되는 클래스는 진입점뿐입니다. 이 경우Client.ClientSpring과 함께 일하기 위해 어떠한 변화도 겪지 않았으며 여전히 [33][34][35]POJO로 남아 있습니다.스프링에 특화된 주석과 콜이 많은 클래스에 분산되지 않도록 함으로써 시스템은 스프링에 [26]대한 의존도를 약간만 유지할 수 있습니다.

각도 JS

다음 예시는 Angular를 보여 줍니다.종속성 주입을 통해 그리팅 서비스를 수신하는 JS 컴포넌트.

기능. 썸클래스(인사하는 사람) {   이것..인사하는 사람 = 인사하는 사람; }  썸클래스.시제품.어떻게 좀 해봐. = 기능.(이름.) {   이것..인사하는 사람.환영하다(이름.); } 

각 각도JS 어플리케이션에는 의존관계 구축 및 룩업을 담당하는 서비스 로케이터가 포함되어 있습니다.

// 모듈에 배선 정보 제공 변화하다 마이 모듈 = 각진.모듈('마이모듈', []);  // 인젝터에게 그리터 서비스 구축 방법을 설명합니다.  // greeter는 $120 서비스에 의존합니다. 마이 모듈.공장 ('카운터', 기능.($140) {   돌아가다 {     환영하다: 기능.(본문) {       $140.경계.(본문);     }   }; }); 

그런 다음 새로운 인젝터를 생성하여 에 정의된 컴포넌트를 제공할 수 있습니다.myModule모듈(그리터 서비스 포함)

변화하다 주입기 = 각진.주입기(['마이모듈', 'ng']); 변화하다 인사하는 사람 = 주입기.얻다('카운터'); 

서비스 로케이터 안티패턴을 피하기 위해 AngularJS에서는 HTML 템플릿에서 선언적 표기법을 사용할 수 있습니다. 이 표기법은 구성 요소 작성을 인젝터에 위임합니다.

<div ng-controller="MyController"> <button ng-click="sayHello()">Hello </button> </div>
기능. 마이 컨트롤러($140, 인사하는 사람) {   $140.안부 전해주세요. = 기능.() {     인사하는 사람.환영하다('Hello World');   }; } 

ng-controllerdirective를 지정하면 인젝터가 컨트롤러와 그 의존관계 인스턴스를 작성하도록 트리거됩니다.

C#

다음 예에서는 C#에서의 컨스트럭터 주입 예를 보여 줍니다.

사용. 시스템.;  네임스페이스 의존주입;  // 클라이언트는 이 인터페이스만 알고 어떤 게임패드를 사용하고 있는지 알 수 없습니다. 인터페이스 IGame패드 기능 {     스트링 Gamepad Name 가져오기();     무효 진동 전력 설정(흘러가다 전력 절약); }  // 다음 서비스는 위의 인터페이스를 구체적으로 구현합니다.  학급 XBox 게임패드 : IGame패드 기능 {     흘러가다 진동 전력 = 1.0f;          일반의 스트링 Gamepad Name 가져오기() => "Xbox 컨트롤러";          일반의 무효 진동 전력 설정(흘러가다 전력 절약) => 진동 전력 = 수학.클램프(전력 절약, 0.0f, 1.0f); }  학급 플레이스테이션조이스틱 : IGame패드 기능 {     흘러가다 진동 전력 = 100.0f;          일반의 스트링 Gamepad Name 가져오기() => "PlayStation 컨트롤러";          일반의 무효 진동 전력 설정(흘러가다 전력 절약) => 진동 전력 = 수학.클램프(전력 절약 * 100.0f, 0.0f, 100.0f); }  학급 스팀 컨트롤러 : IGame패드 기능 {     이중으로 하다 진동 = 1.0;          일반의 스트링 Gamepad Name 가져오기() => "증기 컨트롤러";          일반의 무효 진동 전력 설정(흘러가다 전력 절약) => 진동 = 변환.투더블(수학.클램프(전력 절약, 0.0f, 1.0f)); }  // 이 클래스는 서비스를 받는 클라이언트입니다. 학급 게임패드 {     IGame패드 기능 _Gamepad의 기능;      // 서비스는 컨스트럭터를 통해 주입되어 위 필드에 저장됩니다.     일반의 게임패드(IGame패드 기능 In Gamepad 기능) => _Gamepad의 기능 = In Gamepad 기능;      일반의 무효 쇼케이스()     {         // 주입된 서비스가 사용됩니다.         변화하다 게임패드명 = _Gamepad의 기능.Gamepad Name 가져오기();                  변화하다 메세지 = $"지금 {gamepadName}을(를) 사용하고 있습니다.진동력을 변경하시겠습니까?";                  콘솔.기입선(메세지);     } }  학급 프로그램. {     정적인 무효 주된()     {         변화하다 증기 제어기 = 신규 스팀 컨트롤러();                  // Xbox Controller, Playstation에서도 통과 가능조이스틱 등         // 게임패드는 무엇을 사용하는지 모르기 때문에 사용할 필요가 없습니다.         변화하다 게임 패드 = 신규 게임패드(증기 제어기);                  게임 패드.쇼케이스();     } } 

「 」를 참조해 주세요.

레퍼런스

  1. ^ Seemann, Mark. "Dependency Injection is Loose Coupling". blog.ploeh.dk. Retrieved 2015-07-28.
  2. ^ a b Seeman, Mark (October 2011). Dependency Injection in .NET. Manning Publications. p. 4. ISBN 9781935182504.
  3. ^ Niko Schwarz, Mircea Lungu, Oscar Nierstrasz, "Seuss: 세분화된 구성을 위한 정적 방법으로부터의 책임 분리", 객체 테크놀로지 저널, 제11권, 제1호(2012년 4월), 페이지 3:1-23
  4. ^ "HollywoodPrinciple". c2.com. Retrieved 2015-07-19.
  5. ^ "The Dependency Injection design pattern - Problem, Solution, and Applicability". w3sDesign.com. Retrieved 2017-08-12.
  6. ^ "Passing Information to a Method or a Constructor (The Java™ Tutorials > Learning the Java Language > Classes and Objects)". docs.oracle.com. Retrieved 2015-07-18.
  7. ^ "Inversion of Control vs Dependency Injection". stackoverflow.com. Retrieved 2015-08-05.
  8. ^ "What is the difference between Strategy pattern and Dependency Injection?". stackoverflow.com. Retrieved 2015-07-18.
  9. ^ "Dependency Injection in NET" (PDF). philkildea.co.uk. p. 4. Retrieved 2015-07-18.
  10. ^ "How to explain dependency injection to a 5-year-old?". stackoverflow.com. Retrieved 2015-07-18.
  11. ^ I.T., Titanium. "James Shore: Dependency Injection Demystified". www.jamesshore.com. Retrieved 2015-07-18.
  12. ^ "To "new" or not to "new"…". Retrieved 2015-07-18.
  13. ^ "How to write testable code". www.loosecouplings.com. Retrieved 2015-07-18.
  14. ^ "Writing Clean, Testable Code". www.ethanresnick.com. Retrieved 2015-07-18.
  15. ^ Sironi, Giorgio. "When to inject: the distinction between newables and injectables - Invisible to the eye". www.giorgiosironi.com. Retrieved 2015-07-18.
  16. ^ "the urban canuk, eh: On Dependency Injection and Violating Encapsulation Concerns". www.bryancook.net. Retrieved 2015-07-18.
  17. ^ "The Dependency Injection Design Pattern". msdn.microsoft.com. Retrieved 2015-07-18.
  18. ^ a b "The Java Community Process(SM) Program - JSRs: Java Specification Requests - detail JSR# 330". jcp.org. Retrieved 2015-07-18.
  19. ^ "3.1. Dependency injection — Python 3: from None to Machine Learning". Archived from the original on 2020-02-08.
  20. ^ a b c "How Dependency Injection (DI) Works in Spring Java Application Development - DZone Java".
  21. ^ "Dependency injection and inversion of control in Python — Dependency Injector 4.36.2 documentation".
  22. ^ "How to Refactor for Dependency Injection, Part 3: Larger Applications -".
  23. ^ "A quick intro to Dependency Injection: What it is, and when to use it". 18 October 2018.
  24. ^ "Dependency Injection Professionalqa.com".
  25. ^ "What are the downsides to using Dependency Injection?". stackoverflow.com. Retrieved 2015-07-18.
  26. ^ a b "Dependency Injection Inversion - Clean Coder". sites.google.com. Retrieved 2015-07-18.
  27. ^ "Decoupling Your Application From Your Dependency Injection Framework". InfoQ. Retrieved 2015-07-18.
  28. ^ Martin Fowler (2004-01-23). "Inversion of Control Containers and the Dependency Injection pattern - Forms of Dependency Injection". Martinfowler.com. Retrieved 2014-03-22.
  29. ^ "AccessibleObject (Java Platform SE 7)". docs.oracle.com. Retrieved 2015-07-18.
  30. ^ Riehle, Dirk (2000), Framework Design: A Role Modeling Approach (PDF), Swiss Federal Institute of Technology
  31. ^ "Dependency Injection != using a DI container". www.loosecouplings.com. Retrieved 2015-07-18.
  32. ^ "Black Sheep » DIY-DI » Print". blacksheep.parry.org. Archived from the original on 2015-06-27. Retrieved 2015-07-18.
  33. ^ "Spring Tips: A POJO with annotations is not Plain". Archived from the original on 2015-07-15. Retrieved 2015-07-18.
  34. ^ "Annotations in POJO – a boon or a curse? Techtracer". 2007-04-07. Retrieved 2015-07-18.
  35. ^ Pro Spring Dynamic Modules for OSGi Service Platforms. APress. 2009-02-17. ISBN 9781430216124. Retrieved 2015-07-06.

외부 링크