Injection phụ thuộc và Inversion of Control trong Spring Framework là gì?


111

"Dependency Injection" và "Inversion of Control" thường được đề cập như những lợi thế chính của việc sử dụng Spring framework để phát triển các Web framework

Bất cứ ai có thể giải thích nó là gì trong những thuật ngữ rất đơn giản với một ví dụ nếu có thể?


bản sao có thể có của Inversion of Control là gì?
Steve Chambers

3
@SteveChambers không phải là bản sao của nó, câu hỏi này được hỏi trong Springs Perspective. Câu hỏi đó nói chung là tiền đề.
VdeX

Câu trả lời:


233
  • Spring giúp tạo ra các ứng dụng được kết hợp lỏng lẻo nhờ Dependency Injection .
  • Trong Spring, các đối tượng xác định các liên kết của chúng (phụ thuộc) và đừng lo lắng về cách chúng sẽ lấy các phụ thuộc đó . Spring có trách nhiệm cung cấp các phụ thuộc cần thiết để tạo các đối tượng.

Ví dụ : Giả sử chúng ta có một đối tượng Employeevà nó có phụ thuộc vào đối tượng Address. Chúng ta sẽ định nghĩa một bean tương ứng với Employeenó sẽ xác định sự phụ thuộc của nó vào đối tượng Address.

Khi Spring cố gắng tạo một Employeeđối tượng, nó sẽ thấy đối tượng đó Employeecó phụ thuộc vào Address, vì vậy trước tiên nó sẽ tạo Addressđối tượng (đối tượng phụ thuộc) và sau đó đưa nó vào Employeeđối tượng.

  • Inversion of Control ( IoC ) và Dependency Injection ( DI ) được sử dụng thay thế cho nhau. IoC đạt được thông qua DI. DI là quá trình cung cấp các phụ thuộc và IoC là kết quả cuối cùng của DI. ( Lưu ý: DI không phải là cách duy nhất để đạt được IoC. Ngoài ra còn có nhiều cách khác .)

  • Bởi DI, trách nhiệm tạo các đối tượng được chuyển từ mã ứng dụng của chúng tôi sang vùng chứa Spring; hiện tượng này được gọi là IoC.

  • Dependency Injection có thể được thực hiện bằng cách tiêm setter hoặc tiêm hàm tạo.

Tôi không đồng ý. tôi không nghĩ rằng đây là một lời giải thích rõ ràng. Tại sao bạn không thể khởi tạo "Địa chỉ" bên trong "Nhân viên" thay vì lấy một khuôn khổ để tạo và đưa nó vào? Một ví dụ chi tiết hơn một chút được gọi cho.
Boris

2
@Boris Không ai nói rằng bạn không thể khởi tạo các đối tượng của riêng mình. Nhưng mục đích duy nhất của câu trả lời là để chứng minh cách bạn có thể đạt được điều tương tự với DI. Bạn có thể có cả DI và các đối tượng được khởi tạo bằng mã khách hàng. Điều này vẫn được gọi là IOC, ít nhất là một phần.
bogdan.rusu


Boris. Ghen tị nhiều? Đó là câu trả lời tốt nhất từ ​​trước đến nay.
Aniket Kapse

31

Tôi sẽ viết ra những hiểu biết đơn giản của tôi về hai thuật ngữ này: (Để hiểu nhanh, chỉ cần đọc các ví dụ)

  • Dependency Injection (DI):
    Dependency Injection thường có nghĩa là truyền một đối tượng phụ thuộc làm tham số cho một phương thức, thay vì để phương thức tạo đối tượng phụ thuộc .
    Điều đó có nghĩa là trong thực tế, phương pháp này không phụ thuộc trực tiếp vào việc triển khai cụ thể; bất kỳ triển khai nào đáp ứng các yêu cầu đều có thể được chuyển dưới dạng tham số.

    Với việc thực hiện này các đối tượng xác định các phụ thuộc của chúng. Và mùa xuân làm cho nó có sẵn.
    Điều này dẫn đến việc phát triển ứng dụng được kết hợp lỏng lẻo.

    Ví dụ nhanh: ĐỐI TƯỢNG NHÂN VIÊN KHI ĐƯỢC TẠO, NÓ SẼ TỰ ĐỘNG TẠO ĐỐI TƯỢNG ĐỊA CHỈ (nếu địa chỉ được xác định là phụ thuộc bởi đối tượng Nhân viên) *.

  • Inversion of Control (IoC) Container:
    Đây là đặc điểm chung của các framework, IoC quản lý các đối tượng java
    - từ khởi tạo đến hủy thông qua BeanFactory của nó.
    - Các thành phần Java được khởi tạo bởi vùng chứa IoC được gọi là bean và vùng chứa IoC quản lý phạm vi, sự kiện vòng đời của bean và bất kỳ tính năng AOP nào mà nó đã được cấu hình và mã hóa.

    QUICK EXAMPLE:Inversion of Control is about getting freedom, more flexibility, and less dependency. When you are using a desktop computer, you are slaved (or say, controlled). You have to sit before a screen and look at it. Using keyboard to type and using mouse to navigate. And a bad written software can slave you even more. If you replaced your desktop with a laptop, then you somewhat inverted control. You can easily take it and move around. So now you can control where you are with your computer, instead of computer controlling it.

    Bằng cách triển khai Inversion of Control, người tiêu dùng phần mềm / đối tượng có được nhiều quyền kiểm soát / tùy chọn hơn đối với phần mềm / đối tượng, thay vì bị kiểm soát hoặc có ít tùy chọn hơn.

    Sự đảo ngược kiểm soát như một hướng dẫn thiết kế phục vụ các mục đích sau:
    - Có một sự tách rời việc thực hiện một nhiệm vụ nhất định khỏi việc thực hiện.
    - Mọi mô-đun đều có thể tập trung vào những gì nó được thiết kế.
    - Mô-đun không đưa ra giả định về những gì các hệ thống khác làm mà dựa vào hợp đồng của chúng.
    - Việc thay thế các mô-đun không có tác dụng phụ đối với các mô-đun khác

Tôi sẽ giữ mọi thứ trừu tượng ở đây, bạn có thể truy cập các liên kết sau để hiểu chi tiết về chủ đề.

Một bài đọc hay với ví dụ

Giải thích chi tiết


11

Trong Spring Objects được ghép nối lỏng lẻo, tức là mỗi lớp độc lập với nhau để mọi thứ có thể được kiểm tra riêng lẻ. Nhưng khi sử dụng các lớp đó, một lớp có thể phụ thuộc vào các lớp khác cần được khởi tạo trước.

Vì vậy, chúng ta nói với spring rằng lớp A phụ thuộc vào lớp B. Vì vậy, khi tạo bean (như lớp) cho lớp A, nó khởi tạo lớp B trước lớp A và chèn lớp đó vào lớp A bằng cách sử dụng phương thức setter hoặc constructor DI. Tức là, chúng ta đang nói với mùa xuân sự phụ thuộc vào thời gian chạy. Đây là DI.

Vì chúng tôi đang giao trách nhiệm tạo các đối tượng (bean), duy trì chúng và tổng hợp của chúng vào Spring thay vì mã hóa cứng nó, chúng tôi gọi nó là Inversion Of Control (IOC).


7

Inversion Of Control (IOC):

IoC là một mẫu thiết kế mô tả việc đảo ngược luồng điều khiển trong một hệ thống, vì vậy luồng thực thi không được điều khiển bởi một đoạn mã trung tâm. Điều này có nghĩa là các thành phần chỉ nên phụ thuộc vào sự trừu tượng của các thành phần khác và không chịu trách nhiệm xử lý việc tạo ra các đối tượng phụ thuộc. Thay vào đó, các cá thể đối tượng được cung cấp trong thời gian chạy bởi một vùng chứa IoC thông qua Dependency Injection (DI).

IoC cho phép thiết kế phần mềm tốt hơn, tạo điều kiện sử dụng lại, khớp nối lỏng lẻo và dễ dàng kiểm tra các thành phần phần mềm.

Tiêm phụ thuộc (DI):

DI là một kỹ thuật để truyền các phụ thuộc vào phương thức khởi tạo của một đối tượng. Nếu đối tượng đã được tải từ vùng chứa, thì các phần phụ thuộc của nó sẽ được vùng chứa tự động cung cấp. Điều này cho phép bạn sử dụng một phần phụ thuộc mà không cần phải tạo một cá thể theo cách thủ công. Điều này làm giảm sự ghép nối và cho phép bạn kiểm soát tốt hơn thời gian tồn tại của các cá thể đối tượng.

bấm để xem thêm


6

Spring: Spring là vùng chứa “Inversion of Control” cho Nền tảng Java.

Inversion of Control (IoC): Inversion of Control (IoC) là một thực hành lập trình hướng đối tượng, theo đó việc ghép đối tượng bị ràng buộc trong thời gian chạy bởi một đối tượng "trình hợp dịch" và thường không thể biết được tại thời điểm biên dịch bằng cách sử dụng phân tích tĩnh.

Dependency Injection (DI): "Dependency Injection là một mẫu thiết kế phần mềm cho phép loại bỏ các phần phụ thuộc được mã hóa cứng và giúp bạn có thể thay đổi chúng, cho dù ở thời điểm chạy hay thời gian biên dịch." -wiki.


Làm thế nào điều này bất kỳ đơn giản hơn những gì đã có sẵn (mà câu trả lời này được lấy từ đâu)? Nó không giải thích cho yêu cầu của OP về sự đơn giản, trừ khi các trích dẫn kép xung quanh các thuật ngữ làm cho mọi thứ đơn giản hơn một cách kỳ diệu.
Flame of udun

6

Đảo ngược điều khiển- Nó có nghĩa là trao quyền kiểm soát việc tạo và khởi tạo các spring bean vào vùng chứa Spring IOC và công việc duy nhất mà nhà phát triển làm là định cấu hình các bean trong tệp spring xml.

Tiêm phụ thuộc-

Xem xét một nhân viên trong lớp

class Employee { 
   private int id;
   private String name;
   private Address address;

   Employee() {
     id = 10;
     name="name";
     address = new Address();
   }


}

và xem xét Địa chỉ lớp học

class Address {
   private String street;
   private String city;

   Address() {
     street="test";
     city="test1";

  }
}

Trong đoạn mã trên, các giá trị của lớp địa chỉ sẽ chỉ được đặt khi lớp Nhân viên được khởi tạo, là phần phụ thuộc của lớp Địa chỉ vào lớp Nhân viên. Và Spring giải quyết vấn đề này bằng cách sử dụng khái niệm Dependency Injection bằng cách cung cấp hai cách để tiêm sự phụ thuộc này.

  1. Tiêm định vị

Phương thức setter trong lớp Employee lấy tham chiếu của lớp Address

public void setAddress(Address addr) {
    this.address = addr;
}
  1. Tiêm xây dựng

Hàm tạo trong lớp Nhân viên chấp nhận Địa chỉ

Employee(Address addr) {
      this.address = addr;
}

Bằng cách này, các giá trị của lớp Địa chỉ có thể được đặt độc lập bằng cách sử dụng bộ thiết lập / phương thức chèn.


3

Inversion of Control là một nguyên tắc thiết kế chung của kiến ​​trúc phần mềm hỗ trợ tạo ra các khung phần mềm mô-đun, có thể tái sử dụng và dễ bảo trì.

Đó là một nguyên tắc thiết kế, trong đó Luồng điều khiển được "nhận" từ thư viện được viết chung hoặc mã có thể sử dụng lại.

Để hiểu rõ hơn, hãy xem cách chúng tôi đã sử dụng mã trong những ngày đầu viết mã. Trong các ngôn ngữ thủ tục / truyền thống, logic nghiệp vụ thường kiểm soát luồng của ứng dụng và "Gọi" mã / chức năng chung hoặc có thể tái sử dụng. Ví dụ: trong một ứng dụng Console đơn giản, luồng điều khiển của tôi được kiểm soát bởi các hướng dẫn của chương trình của tôi, có thể bao gồm các lệnh gọi đến một số chức năng có thể tái sử dụng chung.

print ("Please enter your name:");
scan (&name);
print ("Please enter your DOB:");
scan (&dob);

//More print and scan statements
<Do Something Interesting>

//Call a Library function to find the age (common code)
print Age

Ngược lại, với IoC, các Khung công tác là mã có thể tái sử dụng "Gọi" logic nghiệp vụ.

Ví dụ, trong một hệ thống dựa trên cửa sổ, một khuôn khổ sẽ có sẵn để tạo các phần tử giao diện người dùng như các nút, menu, cửa sổ và hộp thoại. Khi tôi viết logic nghiệp vụ của ứng dụng của mình, các sự kiện của khung sẽ gọi mã logic nghiệp vụ của tôi (khi một sự kiện được kích hoạt) chứ KHÔNG phải ngược lại.

Mặc dù, mã của khung công tác không nhận biết được logic nghiệp vụ của tôi, nhưng nó vẫn sẽ biết cách gọi mã của tôi. Điều này đạt được bằng cách sử dụng sự kiện / đại biểu, lệnh gọi lại, v.v. Ở đây Điều khiển luồng là "Đảo ngược".

Vì vậy, thay vì phụ thuộc vào luồng điều khiển trên các đối tượng bị ràng buộc tĩnh, luồng phụ thuộc vào đồ thị đối tượng tổng thể và mối quan hệ giữa các đối tượng khác nhau.

Dependency Injection là một mẫu thiết kế thực hiện nguyên tắc IoC để giải quyết các phụ thuộc của các đối tượng.

Nói cách đơn giản hơn, khi bạn đang cố gắng viết mã, bạn sẽ tạo và sử dụng các lớp khác nhau. Một lớp (Lớp A) có thể sử dụng các lớp khác (Lớp B và / hoặc D). Vì vậy, Lớp B và D là các phụ thuộc của lớp A.

Một phép tương tự đơn giản sẽ là một chiếc Xe hạng. Một chiếc ô tô có thể phụ thuộc vào các lớp khác như Động cơ, Lốp xe và hơn thế nữa.

Dependency Injection gợi ý rằng thay vì các lớp Phụ thuộc (Class Car ở đây) tạo ra các phần phụ thuộc của nó (Class Engine và class Tire), lớp nên được đưa vào với phiên bản cụ thể của phần phụ thuộc.

Hãy hiểu bằng một ví dụ thực tế hơn. Cân nhắc rằng bạn đang viết TextEditor của riêng mình. Trong số những thứ khác, bạn có thể có một trình kiểm tra chính tả cung cấp cho người dùng một phương tiện để kiểm tra lỗi chính tả trong văn bản của họ. Một cách triển khai đơn giản của mã như vậy có thể là:

Class TextEditor
{

    //Lot of rocket science to create the Editor goes here

    EnglishSpellChecker objSpellCheck;
    String text;

    public void TextEditor()

    {   

        objSpellCheck = new EnglishSpellChecker();

    }

    public ArrayList <typos> CheckSpellings()
    {

        //return Typos;

    }

}

Ngay từ cái nhìn đầu tiên, tất cả đều trông hồng hào. Người dùng sẽ viết một số văn bản. Nhà phát triển sẽ nắm bắt văn bản và gọi chức năng CheckSpellings và sẽ tìm thấy danh sách các Typos mà anh ta sẽ hiển thị cho Người dùng.

Mọi thứ dường như hoạt động tốt cho đến một ngày đẹp trời khi một người dùng bắt đầu viết tiếng Pháp trong Trình chỉnh sửa.

Để cung cấp hỗ trợ cho nhiều ngôn ngữ hơn, chúng tôi cần có nhiều Trình kiểm tra chính tả hơn. Có thể là tiếng Pháp, tiếng Đức, tiếng Tây Ban Nha, v.v.

Ở đây, chúng tôi đã tạo một mã kết hợp chặt chẽ với SpellChecker "tiếng Anh" được kết hợp chặt chẽ với lớp TextEditor của chúng tôi, có nghĩa là lớp TextEditor của chúng tôi phụ thuộc vào EnglishSpellChecker hay nói cách khác EnglishSpellCheker là phần phụ thuộc của TextEditor. Chúng ta cần loại bỏ sự phụ thuộc này. Hơn nữa, Trình soạn thảo văn bản của chúng tôi cần một cách để giữ tham chiếu cụ thể của bất kỳ Trình kiểm tra chính tả nào dựa trên quyết định của nhà phát triển tại thời điểm chạy.

Vì vậy, như chúng ta đã thấy trong phần giới thiệu của DI, nó gợi ý rằng lớp nên được đưa vào các phụ thuộc của nó. Vì vậy, trách nhiệm của mã gọi là đưa tất cả các phụ thuộc vào lớp / mã được gọi. Vì vậy, chúng tôi có thể cấu trúc lại mã của mình như

interface ISpellChecker
{

    Arraylist<typos> CheckSpelling(string Text);

}

Class EnglishSpellChecker : ISpellChecker

{

    public override Arraylist<typos> CheckSpelling(string Text)

    {

        //All Magic goes here.

    }

}



Class FrenchSpellChecker : ISpellChecker

{

    public override Arraylist<typos> CheckSpelling(string Text)

    {

        //All Magic goes here.

    }

}

Trong ví dụ của chúng tôi, lớp TextEditor sẽ nhận được phiên bản cụ thể của loại ISpellChecker.

Bây giờ, phụ thuộc có thể được đưa vào Constructor, một Thuộc tính Công cộng hoặc một phương thức.

Hãy thử thay đổi lớp của chúng ta bằng Constructor DI. Lớp TextEditor đã thay đổi sẽ trông giống như sau:

Class TextEditor

{

    ISpellChecker objSpellChecker;

    string Text;



    public void TextEditor(ISpellChecker objSC)

    {

        objSpellChecker = objSC;

    }



    public ArrayList <typos> CheckSpellings()

    {

        return objSpellChecker.CheckSpelling();

    }

}

Để mã gọi, trong khi tạo trình soạn thảo văn bản có thể đưa Loại SpellChecker thích hợp vào bản sao của TextEditor.

Bạn có thể đọc toàn bộ bài viết tại đây


1

Cách truyền thống để lấy thể hiện địa chỉ trong Employee sẽ là tạo một thể hiện mới của lớp Address. Pring tạo ra tất cả các đối tượng phụ thuộc cho chúng ta, do đó chúng ta không cần lo lắng về đối tượng.

Vì vậy, trong Spring, chúng ta chỉ phụ thuộc vào vùng chứa lò xo cung cấp cho chúng ta đối tượng phụ thuộc.


1

IOC là kỹ thuật mà bạn để người khác tạo đối tượng cho bạn. Và một người khác trong trường hợp mùa xuân là IOC container.

Dependency Injection là một kỹ thuật trong đó một đối tượng cung cấp sự phụ thuộc của một đối tượng khác.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.