反射機制
正向: 代碼->dll, 先編碼, 定義好類,通過實例化對象來調用之.
反向: dll->類[方法,屬性]. 從已經有的dll文件反編譯得到其中的一些可用的方法.
審查元數據並收集關於它的類型信息的能力。元數據(編譯以后的最基本數據單元)就是一大堆的表,當編譯程序集或者模塊時,編譯器會創建一個類定義表,一個字段定義表,和一個方法定義表等。
System.reflection命名空間包含的幾個類,允許你反射(解析)這些元數據表的代碼。
反射是.Net中獲取 運行時類型信息的方式,.Net的應用程序由幾個部分:'程序集(Assembly)’、'模塊(Module)’、'類型(class)’組成,而反射提供一種編程的方式,讓程序員可以在程序運行期獲得這幾個組成部分的相關信息,例如:
通常程序員面試題,有這樣關於反射的解釋:反射可以動態地創建類型的實例,還可以將類型綁定到現有對象,或從現有對象中獲取類型。然后,可以調用類型的方法或訪問其字段和屬性。
主要用途是:通過傳遞一個字符串值, 在運行時構造一個類的對象, 判斷一個類所具有的成員變量和方法;調用一個對象的方法;生成動態代理。反射最大的應用就是框架
正常處理過程:系統在運行的時候將把dll(動態鏈接庫)加載到當 前進程的一個默認的應用程序域application.currentdomain.load方法可以取得當前域的所有dll,也可以unload方法將 dll從該域卸載掉,通過執行dll的方法來響應用戶的操作,執行完后,就釋放了這個dll,這是運行時的行為這里dll相當於一個工具集, 工具箱. 用戶只得到這個工具箱, 按下相應接口按鈕可以完成對應的任務。
反射: 反過來看,你可以從當前進程的應用程序域取得DLL開始(application.currentdomain.load取出該進程的所有的DLL列表),取得DLL里的類列表或者其他模塊,然后調用類的方法,相當於打開了工具箱, 取其中的一些工具來.
也就是說,正常的順序是,知道一個確定的類以及里面的屬性、方法。然后實例化一個對象,調用它的方法來執行。
反射就是只有一個DLL文件,知道類名卻不知道他有什么屬性和方法,可以通過反射機制來動態加載程序集得到類中的屬性、方法信息,並實例化一個對象等
例如本來有一個類
namespace A{
public class A{
public int methodA(string s);
public int methodB(int i);
public int c;
}
}
如果只給你這個dll工程編譯出的dll文件
可以用system.reflection中的一些個方法來得到其中的具體的屬性/方法等..
string asmFile = "path of dll".
System.Reflection.Assembly asm = System.Reflection.Assembly.LoadFrom(asmFile) ;
MemberInfo[] mi = asm.GetType(asmName + "." + asmName).GetMethods();
Type t = asm.GetType(命名空間.類名); 用t來訪問具體的方法..
類名: method = System.Activator.CreateInstance(t);
類名可以通過getname來得到..
總結反射:
別被嚇唬了,原理其實很簡單,.net所編寫的程序集包含兩個重要部分:IL(中間語言代碼) 和metadata(元數據)。我們編寫的代碼中不是有很多很多的類嗎,類有很多很多的成員,在編譯代碼的時候,元數據表就根據代碼把類的所有信息都記錄在了它里面(其實它就是一個數據結構,組織類的信息)。
而反射的過程剛好相反,就是通過元數據里記錄的關於類的詳細信息找到該類的成員,並能使它“復活”(因為元數據里所記錄的信息足夠詳細,以致於可以根據metadata里面記錄的信息找到關於該類的IL code並加以利用)。
最后對比下:
元數據形成:根據代碼具體內容形成類的記錄信息;
反射:根據元數據的記錄找到所需的代碼;
至於實例,用Type類實現很方便:
Type t = typeof(System.string);
MemberInfo[] mis = t.GetMembers();
foreach (MemberInfo mi in mis)
{
Console.WriteLine(mi.MemberType + mi.Name);
}
就會得到關於String類的所有信息;
控制反轉、依賴注入
控制反轉(Inversion of Control,英文縮寫為IoC)是一個重要的面向對象編程的法則來削減計算機程序的耦合問題,也是輕量級的Spring框架的核心。 控制反轉一般分為兩種類型,依賴注入(Dependency Injection,簡稱DI)和依賴查找(Dependency Lookup)。依賴注入應用比較廣泛。
依賴注入:
依賴注入和控制反轉是同一個概念。具體含義是: 當某個角色(一個實例,調用者)需要另一個角色(另一個實例,被調用者)的協助時,在傳統的程序設計過程中,通常有調用者來創建被調用者的實例。但在 Spring里,創建被調用者的工作不再由調用者來完成,因此成為控制反轉;創建被調用者實例的工作通常有Spring容器來完成,然后注入到調用者,因 此也稱為依賴注入。
不管是依賴注入,還是控制反轉,多說明Spring采用動態、靈活的方式來管理各種對象。對象與對象之間的具體實現相互透明。看如下這個問題在各種社會形態里如何解決:一個人(實例,調用者)需要一把斧子(實例,被調用者)。
(1).原始社會里,幾乎沒有社會分工。需要一把斧子的人(調用者)只能自己去磨一把斧子(被調用者)。對應的情形為:Java或C#程序里的調用者自己創建被調用者。
(2).進入工業社會,工廠出現。斧子不再由普通人完成,而在工廠里被生產出來,此時需要斧子的人(調用者)找到工廠,購買斧子,無需關系斧子的制造過程。對應程序的簡單工廠設計模式。
(3).進入“按需分配”社會,需要斧子的人不需要找到工廠,坐在家里發出一個簡單指令:需要斧子。斧子就自然出現在它面前。對應Spring的依賴注入。
第一種情況下,Java或C#實例的調用者創建被調用的實例,必然要求被調用的類出現在調用者的代碼里。無法實現二者之間的松耦合。
第二種情況下,調用者無需關心被調用者具體實現過程,只需要找到符合某種標准(接口)的實例,即可使用。此時調用的代碼面向接口編程,可以讓調用者和被調用者解耦,這也是工廠模式大量使用的原因。但調用者需要自己定位工廠,調用者與特定工廠耦合在一起。
第三種情況下,調用者無需自己定位工廠,程序運行到需要被調用者時,系統自動提供被調用者實例。事實上,調用者和被調用者都處於Spring的管理下,二者之間的依賴關系有Spring提供。
所謂依賴注入,是指程序運行過程中,如果需要調用另一個對象協助時,無需在代碼中創建被調用者,而是依賴於外部的注入。Spring的依賴注入對調用者和被調用者幾乎沒有任何要求,完全支持對POJO之間依賴關系的管理。
依賴注入(控制反轉)是Spring框架的核心。
應用控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體(可以理解為后面所說的容器)將其所依賴的對象的引用傳遞給它。也可以說,依賴被注入到對象中。所以,控制反轉是,關於一個對象如何獲取他所依賴的對象的引用,這個責任的反轉。原來依賴關系是調用者調用被調用者,現在反過來是被調用者注冊到調用者。
換句話說,就是在運行的時候才產生調用者實例和被調用者實例之間的依賴關系(吧這 種依賴關系在一個合適的時候“注入”運行時),恐怕就是DI(Dependency Injection)這個術語的由來。再換句話說,我們提到過解除強依賴,這並不是說調用者和被調用者之間的一覽關系不存在了,事實上調用者無論如何也需 要某類被調用者提供的服務,我們只是把何種依賴的建立時間推后了,從編譯器推遲到了運行時。依賴關系在OO程序中是廣泛存在的,只要A類型中用到了B類型 實例,A就依賴於B。前面筆者淡到的內容是把概念抽象到了服務使用者和服務提供者的角度,這也符合現在SOA的設計思路。從另一種抽象方式上來看,可以把 調用者看成我們要構建的主系統,而被調用者實例是系統中的plugin,主系統並不強依賴於任何一個插件,但一旦插件被加載,主系統就應該可以准確調用適 當插件的功能。
其實不管是面向服務的編程模式,還是基於插件的框架式編程,為了實現松耦合(服務調用者和提供者之間的or框架和插件之間的),都需要在必要的位置實現面向接口編程,在此基礎之上,還應該有一種方便的機制實現具體類型之間的運行時綁定,這就是DI所要解決的問題。
說白了,就是要提供一個容器,由容器來完成(1)具體ServiceProvider的創建(2)ServiceUser和ServiceProvider的運行時綁定。特別說明的是,要理解依賴注入的機制,關鍵是理解容器的實現方式。
IoC可以認為是一種全新的設計模式,但是理論和時間成熟相對較晚,並沒有包含在GoF中。
Interface Driven Design接口驅動,接口驅動有很多好處,可以提供不同靈活的子類實現,增加代碼穩定和健壯性等等,但是接口一定是需要實現的,也就是如下語句遲早要執行:AInterface a = new AInterfaceImp(); 這樣一來,耦合關系就產生了,如:
Class A與AInterfaceImp就是依賴關系,如果想使用AInterface的另外一個實現就需要更改代碼了。當然我們可以建立一個Factory來根據條件生成想要的AInterface的具體實現,即:
表面上是在一定程度上緩解了以上問題,但實質上這種代碼耦合並沒有改變。通過IoC模式可以徹底解決這種耦合,它把耦合從代碼中移出去,放到統一的XML 文件中,通過一個容器在需要的時候把這個依賴關系形成,即把需要的接口實現注入到需要它的類中,這可能就是“依賴注入”說法的來源了。
IOC模式,系統中通過引入實現了IOC模式的IOC容器,即可由IOC容器來管理對象的生命周期、依賴關系等,從而使得應用程序的配置和依賴性規范與實際的應用程序代碼分開。其中一個特點就是通過文本的配置文件進行應用程序組件間相互關系的配置,而不用重新修改並編譯具體的代碼。
當前比較知名的IOC容器有:Pico Container、Avalon 、Spring、JBoss、HiveMind、EJB等。
在上面的幾個IOC容器中,輕量級的有Pico Container、Avalon、Spring、HiveMind等,超重量級的有EJB,而半輕半重的有容器有JBoss,Jdon等。
可以把IoC模式看做是工廠模式的升華,可以把IoC看作是一個大工廠,只不過這個大工廠里要生成的對象都是在XML文件中給出定義的,然后利用Java 的“反射”編程,根據XML中給出的類名生成相應的對象。從實現來看,IoC是把以前在工廠方法里寫死的對象生成代碼,改變為由XML文件來定義,也就是把工廠和對象生成這兩者獨立分隔開來,目的就是提高靈活性和可維護性。
IoC中最基本的Java技術就是“反射”編程。反射又是一個生澀的名詞,通俗的說反射就是根據給出的類名(字符串)來生成對象。這種編程方式可以讓對象在生成時才決定要生成哪一種對象。反射的應用是很廣泛的,象Hibernate、Spring中都是用“反射”做為最基本的技術手段。
在過去,反射編程方式相對於正常的對象生成方式要慢10幾倍,這也許也是當時為什么反射技術沒有普遍應用開來的原因。但經SUN改良優化后,反射方式生成對象和通常對象生成方式,速度已經相差不大了(但依然有一倍以上的差距)。