1. 程式人生 > >我的控制反轉,依賴注入和麵向切面程式設計的理解

我的控制反轉,依賴注入和麵向切面程式設計的理解

1.什麼是控制? 如下圖所示,我們看到了 軟體系統中 物件的 高耦合現象。全體齒輪的轉動由一個物件來控制,如類B。
2.什麼是 控制反轉? 是用來對物件進行解耦藉助第三方實現具有依賴關係的的物件之間的解耦。這個第三方就是 ioc 容器。引入了 ioc 容器後,物件 A、B、C、D 之間沒有了依賴關係全體齒輪轉動的控制權交給 容器。這時候齒輪轉動控制權不屬於任何物件,而屬於ioc 容器,所以控制權反轉了,從 某個物件 轉到了 ioc 容器。
3. 什麼是依賴注入? 3.1 什麼是依賴?依賴就是指一種關係,如果 在類A中 建立了 類B的例項,我們說 類A 依賴 類B。 3.2 看個荔枝:
public class class A{
B b;
public A(){
b = new B();
}
void func(){
b.func();
}
}
出現的問題(problems):
  • 問題1:如果現在要改變 類 B 生成方式,如需要用new B(String name)初始化 B,需要修改 類A中的原始碼;
  • 問題2:如果想測試不同 B 物件對 A 的影響很困難,因為 B 的初始化被寫死在了 A 的建構函式中
  • 問題3:如果要對類B的例項進行除錯時,就必須在類A中對類B的例項進行測試,增加了測試難度和複雜度;因為當出現問題時,不知道 是 類A的問題 還是 類B的問題;
解決方法:
public class class A{
B b;
public A(B b){
this.b = b;
}
void func(){
b.func();
}
}
3.3)依賴注入定義: 將B物件例項 作為類A的構造器引數進行傳入,在呼叫類A 構造器之前,類B例項已經被初始化好了。像這種非自己主動初始化依賴,而通過外部傳入依賴物件的方式,我們就稱為依賴注入 4.依賴反轉 4.1 根據依賴注入的定義: 被依賴者物件並不是依賴者自己主動初始化,而是通過外部傳入被依賴者的方式,那麼被依賴者物件型別 可以是 其 本身,也可以使其實現類或繼承子類; 4.2 所以,經過分析,被依賴者的物件型別 並不是 依賴者自身可以決定的,(當然傳統的程式設計方式是依賴者 決定的),而是由外部建立者決定的,所以 被依賴者型別的決定權反轉了。對於spirng來說 ,就是由 spring容器決定的;
4.3 依賴反轉定義:被依賴者的 物件型別 並不是由依賴者自身可以決定的,而是由 外部建立者決定的,外部傳入什麼型別的物件 就是 什麼型別的物件 , 依賴者對其一無所知; ======================================================================================= 【AOP 【1】What is it? 面向切面程式設計是什麼? 1)切面定義:一個切面是通常指散佈在方法,類,物件層次結構或甚至整個物件模型中的共同特徵。 它是看起來和氣味的行為差不多,它應該有結構,但你不能用程式碼在傳統的面向物件技術中表示這種結構。 2)切面荔枝:例如,度量(時間,用於度量執行某個程式碼片需要花費多長時間)是一個常見切面。 要從應用程式生成有用的日誌,您必須(通常自由地)在程式碼中散佈資訊性訊息。 然而,度量是你的類或物件模型真正不應該關注的東西。 畢竟,度量與您的實際應用無關:它不代表客戶或帳戶,並且不實現業務規則。 它只是正交。 3)橫切關注點定義:在AOP中,像度量這樣的特徵稱為橫切關注點,因為它是一種“截斷”物件模型中多個點但仍然截然不同的行為。作為一種開發方法,AOP建議您抽象和封裝橫切關注點。 4)橫切關注點荔枝:例如,假設您想要嚮應用程式新增程式碼以測量呼叫特定方法所需的時間。 在純Java中,程式碼看起來像下面這樣。
public class BankAccountDAO {
  public void withdraw(double amount)  {
    long startTime = System.currentTimeMillis();
    try {
      // Actual method body...
    }
    finally {
      long endTime = System.currentTimeMillis() - startTime;
      System.out.println("withdraw took: " + endTime);
    }
  }
}
程式碼分析)雖然這段程式碼工作,這個方法有一些問題:
  • 開啟和關閉指標是非常困難的,因為您必須手動將try> / finally塊中的程式碼新增到要基準的每個方法或建構函式。
  • 分析程式碼真的不屬於你的應用程式程式碼。 它使你的程式碼膨脹和更難讀,因為你必須在一個try / finally塊中包含時間。
  • 如果要擴充套件此功能以包括方法或失敗計數,或者甚至將這些統計資訊註冊到更復雜的報告機制,則必須再次修改許多不同的檔案。
這種度量方法很難維護,擴充套件和擴充套件,因為它分散在整個程式碼庫中。 這只是一個很小的例子! 在許多情況下,OOP可能不總是向類新增指標的最佳方法。 面向方面的程式設計提供了一種封裝這種型別的行為功能的方法。 它允許您新增行為,如度量“圍繞”您的程式碼。 例如,AOP為您提供了程式控制,以指定您希望在執行程式碼的實際主體之前呼叫BankAccountDAO來執行度量方面。 【2】在JBoss 切面程式設計中建立切面 1)簡而言之,所有AOP框架定義了兩個東西:一種實現橫切關注點的方法,以及一個程式語言或一組標籤 -以指定如何應用這些程式碼片段。(一種是 定義橫切關注點的方法,二是指定該橫切關注點在何處使用) 2)讓我們來看看JBoss AOP,它的橫切關注點,以及如何在JBoss中實現一個度量方面。 在JBoss AOP中建立度量方面的第一步是將度量特性封裝在自己的Java類中。 清單二將清單One的BankAccountDAO.withdraw()方法中的try / finally塊提取為Metrics,這是一個JBoss AOP攔截器類的實現。 清單二:在JBoss AOP攔截器中實現度量
public class Metrics implements org.jboss.aop.Interceptor
03.   public Object invoke(Invocation invocation) throws Throwable {
05.     long startTime = System.currentTimeMillis();
06.     try {
08.       return invocation.invokeNext();
09.     }
10.     finally {
12.       long endTime = System.currentTimeMillis() - startTime;
13.       java.lang.reflect.Method m = ((MethodInvocation)invocation).method;
14.       System.out.println("method " + m.toString() + " time: " + endTime + "ms");
15.     }
16.   }
17. }
對以上程式碼的分析:
  • 在JBoss AOP下,Metrics類包裝withdraw():當呼叫程式碼呼叫withdraw()時,AOP框架將方法呼叫分解為其部分,並將這些部分封裝到一個呼叫物件中。 然後框架呼叫位於呼叫程式碼和實際方法體之間的任何方面。
  • 當AOP框架解析方法呼叫時,它在第3行呼叫Metric的invoke方法。第8行包裝並委託給實際的方法,並使用一個封閉的try / finally塊來執行定時。 第13行從呼叫物件獲取有關方法呼叫的上下文資訊,而第14行顯示方法名稱和計算的度量。
  • 將度量程式碼放在其自己的物件中允許我們以後輕鬆擴充套件和捕獲額外的測量。現在,度量被封裝到一個方面,讓我們看看如何應用它。
【3】JBoss AOP中切面的應用 要應用一個方面,您定義何時執行方面程式碼。 這些執行點被稱為切入點。 類似於切入點是一個正則表示式。 正則表示式匹配字串時,切入點表示式匹配應用程式中的事件/點。 例如,有效的切入點定義將是“對於JDBC方法executeQuery()的所有呼叫,呼叫驗證SQL語法的方面”。 我的總結(AOP) 1)切面的抽象型定義:切面是散佈在 方法,類,物件層次結構或 整個物件模型中的共同特徵;(是一組特徵) 2)切面荔枝:如 我們要對某方法的執行時間進行統計,程式碼如下:
public class BankAccountDAO {
  public void withdraw(double amount)  {
    long startTime = System.currentTimeMillis();
    try {
      // Actual method body...
    }
    finally {
      long endTime = System.currentTimeMillis() - startTime;
      System.out.println("withdraw took: " + endTime);
    }
  }
}
其中 有關於統計時間的都是特徵,它們的共性都是因為要統計時間而 新增到 方法中的程式碼塊;那所以這些程式碼塊就組成了 切面; 3)以上程式碼塊出現了問題 問題1)程式碼重用率低:必須手動將該 切面程式碼新增到 要統計方法執行時間的方法中; 問題2)程式碼膨脹和可讀性低:計時程式碼真的不用你去關心,這些切面程式碼只會讓你的程式碼更加 膨脹和難讀,因為你必須在一個try / finally塊中包含時間, 但這個時間與我們 方法的執行沒有任何關係; 問題3)不利於程式碼擴充套件(程式碼耦合性高):如果要擴充套件此功能以包括方法或失敗計數,或者甚至將這些統計資訊註冊到更復雜的報告機制,則必須再次修改許多不同的檔案; 最後的最後:這種時間度量方法很難維護,擴充套件和擴充套件,因為它分散在整個程式碼庫中; 4)aop 是幹什麼的? 4.1)intro:面向切面程式設計提供了一種封裝切面行為的方法。AOP提供了程式控制,以指定您希望在執行程式碼的實際主體之前呼叫 時間統計方法 來執行執行時間度量。 4.2)所有AOP框架定義了兩個東西:一種實現橫切關注點的方法,以及一個程式語言或一組標籤 -以指定如何應用這些程式碼片段。(一種是 定義橫切關注點的方法,二是指定該橫切關注點在何時何處使用) 5)如何定義aop中橫切關注點的方法 和 指定該橫切關注點的應用地點 5.1)定義橫切關注點:將切面程式碼度量特性封裝在自己的Java類中
public class Metrics implements org.jboss.aop.Interceptor
   public Object invoke(Invocation invocation) throws Throwable {
     long startTime = System.currentTimeMillis();
     try {
       return invocation.invokeNext(); // 呼叫真正的實體方法
     }
     finally {
       long endTime = System.currentTimeMillis() - startTime;
       java.lang.reflect.Method m = ((MethodInvocation)invocation).method;
       System.out.println("method " + m.toString() + " time: " + endTime + "ms");
     }
   }
 }
5.2)橫切關注點在何時何地使用? 要應用一個切面,您定義何時執行切面程式碼。 這些執行點被稱為切入點。切入點類似於是一個正則表示式。 正則表示式匹配字串時,切入點表示式匹配應用程式中的事件/點。 看個 切入點的定義: @Before("execution(** concert.Performance.perform(..))")