好程式設計師Java乾貨分享Spring框架之IOC原理

好程式設計師IT發表於2019-07-09

好程式設計師 Java 乾貨分享 Spring 框架之 IOC 原理, 前言:Spring 框架是我們進行企業級開發的最常用框架,本章我們將瞭解 Spring 框架,並學習 Spring IOC 特性以及 IOC 的實現原理:註解和反射。

Spring 框架簡介

   Spring 是一種輕量級的控制反轉( IOC )和麵向切面程式設計( AOP )的容器框架,能夠為企業級開發提供一站式服務。

   Spring 的優點有

   1. 方便解耦,簡化開發

  透過 Spring 提供的 IoC 容器,我們可以將物件之間的依賴關係交由 Spring 進行控制,避免硬編碼所造成的過度程式耦合。有了 Spring ,使用者不必再為單例項模式類、屬性檔案解析等這些很底層的需求編寫程式碼,可以更專注於上層的應用。

   2.AOP 程式設計的支援

  透過 Spring 提供的 AOP 功能,方便進行面向切面的程式設計,許多不容易用傳統 OOP 實現的功能可以透過 AOP 輕鬆應付。

   3. 宣告式事務的支援

  在 Spring 中,我們可以從單調煩悶的事務管理程式碼中解脫出來,透過宣告式方式靈活地進行事務的管理,提高開發效率和質量。

   4. 方便程式的測試

  可以用非容器依賴的程式設計方式進行幾乎所有的測試工作,在 Spring 裡,測試不再是昂貴的操作,而是隨手可做的事情。例如: Spring Junit4 支援,可以透過註解方便的測試 Spring 程式。

   5. 方便整合各種優秀框架

   Spring 不排斥各種優秀的開源框架,相反, Spring 可以降低各種框架的使用難度, Spring 提供了對各種優秀框架(如 Struts,Hibernate Hessian Quartz )等的直接支援。

   6. 降低 Java EE API 的使用難度

   Spring 對很多難用的 Java EE API (如 JDBC JavaMail ,遠端呼叫等)提供了一個薄薄的封裝層,透過 Spring 的簡易封裝,這些 Java EE API 的使用難度大為降低。

  

Spring 的組成


   Spring Core Spring  框架的核心。 Spring 其它元件都依賴於核心元件,主要透過 BeanFactory 提供 IOC 等服務。

   Spring Context Sprin 上下文是一個配置檔案,向  Spring 框架提供上下文資訊。 Spring  上下文包括企業服務,例如 JNDI EJB 、電子郵件、國際化、校驗和排程功能。

   Spring AOP :透過配置管理特性, Spring AOP  模組直接將面向切面的程式設計功能整合到了  Spring  框架中。

   Spring ORM Spring  框架插入了若干個 ORM 框架,從而提供了  ORM  的物件關係工具,其中包括 JDO Hibernate iBatisSQL Map 。所有這些都遵從  Spring  的通用事務和  DAO  異常層次結構。

   Spring DAO:  DAO 抽象層提供了有意義的異常層次結構,可用該結構來管理異常處理和不同資料庫供應商丟擲的錯誤訊息。異常層次結構簡化了錯誤處理,並且極大地降低了需要編寫的異常程式碼數量(例如開啟和關閉連線)。 Spring DAO  的面向  JDBC  的異常遵從通用的  DAO  異常層次結構。

   Spring Web:  Web  上下文模組建立在應用程式上下文模組之上,為基於  Web  的應用程式提供了上下文。所以, Spring 框架支援與  Jakarta Struts  的整合。 Web  模組還簡化了處理多部分請求以及將請求引數繫結到域物件的工作。

   Spring Web MVC:  為  web  應用提供了模型檢視控制( MVC )和  REST Web  服務的實現。 Spring  的  MVC  框架可以使領域模型程式碼和  web  表單完全地分離,且可以與  Spring  框架的其它所有功能進行整合。

  

IOC DI

   IOC Inverse Of Control )是控制反轉的意思,作用是降低物件之間的耦合度。

  一般情況下我們直接在物件內部透過 new 進行建立物件,是程式主動去建立依賴物件;而 IoC 是有專門一個容器來建立這些物件,即由 Ioc 容器來控制物件的建立;這樣就是由容器來控制物件,而不是由我們的物件來控制,這樣就完成了控制反轉。

   DI(Dependency Injection )即“依賴注入”:是元件之間依賴關係由容器在執行期決定,形象的說,即由容器動態的將某個依賴關係注入到元件之中。依賴注入的目的並非為軟體系統帶來更多功能,而是為了提升元件重用的頻率,併為系統搭建一個靈活、可擴充套件的平臺。透過依賴注入機制,我們只需要透過簡單的配置,而無需任何程式碼就可指定目標需要的資源,完成自身的業務邏輯,而不需要關心具體的資源來自何處,由誰實現。

  

IOC 的原理:註解 + 反射

下面的案例講解了 IOC 的原理,模擬為電腦配置不同的 CPU 和記憶體, CPU AMD INTEL 兩種,記憶體有 DDR8G DDR16G 兩種

  1. /**
  2. * CPU 介面
  3. */
  4. public interface Cpu {
  5. void run();
  6. }
  7. /**
  8. 記憶體介面
  9. */
  10. public interface Memory {
  11. void read();
  12. void write();
  13. }
  14. /**
  15. * AMD CPU
  16. */
  17. public class AMDCpu implements Cpu {
  18. public void run() {
  19. System.out.println("AMD CPU 正在執行 ....");
  20. }
  21. }
  22. /**
  23. * Intel CPU
  24. */
  25. public class IntelCpu implements Cpu{
  26. public void run() {
  27. System.out.println("Intel CPU 正在執行 ....");
  28. }
  29. }
  30. /**
  31. * DDR8G 的記憶體
  32. */
  33. public class DDR8GMemory implements Memory {
  34. public void read() {
  35. System.out.println(" 使用 DDR8G 的記憶體讀取資料 ....");
  36. }
  37. public void write() {
  38. System.out.println(" 使用 DDR8G 的記憶體寫入資料 ....");
  39. }
  40. }
  41. /**
  42. * DDR16G 的記憶體
  43. */
  44. public class DDR16GMemory implements Memory {
  45. public void read() {
  46. System.out.println(" 使用 DDR16G 的記憶體讀取資料 ....");
  47. }
  48. public void write() {
  49. System.out.println(" 使用 DDR16G 的記憶體寫入資料 ....");
  50. }
  51. }
  52. public class TestComputer {
  53. @Test
  54. public void testComputer(){
  55. // 硬編碼方式建立物件
  56. Computer computer = new Computer();
  57. Cpu cpu = new IntelCpu();
  58. Memory memory = new DDR16GMemory();
  59. computer.setCpu(cpu);
  60. computer.setMemory(memory);
  61. computer.start();
  62. }
  63. }

 

上面是使用硬編碼方式建立電腦的 CPU 和記憶體屬性,程式碼和具體的子類緊密耦合,不利於後期的維護和擴充套件。

修改的思路是:不由讓程式主動建立去建立 CPU 和記憶體物件,而是透過註解方式標記 CPU 和記憶體的型別,使用反射將 CPU 和記憶體的物件注入到電腦的屬性中。

新增程式碼:

  1. /**
  2. 電腦元件的註解
  3. */
  4. @Retention(RetentionPolicy.RUNTIME)
  5. @Target(ElementType.FIELD)
  6. public @interface MyComponent {
  7. /**
  8. 元件型別
  9. * @return
  10. */
  11. Class componentClass();
  12. }
  13. /**
  14. 電腦類
  15. */
  16. public class Computer {
  17. @MyComponent(componentClass = IntelCpu.class)
  18. private Cpu cpu;
  19. @MyComponent(componentClass = DDR8GMemory.class)
  20. private Memory memory;
  21. ....}
  22. public class TestComputer {
  23. @Test
  24. public void testComputer(){
  25. // 透過反射和註解,將 cpu memory 屬性注入進去
  26. try {
  27. // 獲得 Computer 型別
  28. Class<Computer> computerClass = Computer.class;
  29. // 建立 Computer 物件
  30. Computer computer = computerClass.newInstance();
  31. // 獲得 Computer 物件的屬性
  32. Field[] fields = computerClass.getDeclaredFields();
  33. // 遍歷屬性
  34. for(Field field : fields){
  35. // 獲得屬性上定義的 MyComponent 註解
  36. MyComponent anno = field.getDeclaredAnnotation(MyComponent.class);
  37. // 獲得配置的元件型別
  38. Class aClass = anno.componentClass();
  39. // 建立該元件的物件
  40. Object comp = aClass.newInstance();
  41. // 呼叫 set 方法賦值給屬性
  42. String name = field.getName();
  43. name = "set" + name.substring(0,1).toUpperCase() + name.substring(1);
  44. // 透過方法名和引數型別獲得方法
  45. Method method = computerClass.getDeclaredMethod(name, field.getType());
  46. // 呼叫方法
  47. method.invoke(computer,comp);
  48. }
  49. // 啟動電腦
  50. computer.start();
  51. } catch (Exception e) {
  52. e.printStackTrace();
  53. }
  54. }
  55. }

程式如上面修改後,後期如果需要修改電腦的配置,只需要修改註解配置的型別,就可以注入不同的電腦元件,這樣就降低了程式碼間的耦合性,維護程式碼變得比較簡單。

  @MyComponent(componentClass = AMDCpu.class)

    private Cpu cpu;

 

  @MyComponent(componentClass = DDR16GMemory.class)

   private Memory memory;

 

總結

IOC (控制反轉)是 Spring 最重要的原理,它將建立物件的主動權交給 Spring 容器, Spring 程式只需要進行一些配置,就可以使用不同的物件,極大的降低了程式碼耦合性,提高了程式的靈活性, IOC 的實現原理是反射機制。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913892/viewspace-2649996/,如需轉載,請註明出處,否則將追究法律責任。

相關文章