第四章 Spring.Net 如何管理您的類___自定義對象行為


    Spring.Net 一直講求 ” 配置應用程序“,有一種需求在實際開發中不太常用,卻非常有用 -> 配置對象的行為,Spring.Net 也能夠完美的實現。Spring.Net 通過幾個專門的接口來控制容器中對象的行為。比如說,我們可以自定義對象初始化行為,自定義對象銷毀行為,抽象對象定義和子對象定義等。在下面會介紹常用的幾中 自定義對象行為:

① 自定義對象初始化行為

② 自定義對象銷毀行為

③ 抽象對象定義

④ 子對象定義

⑤ IObjectPostProcessor及擴展類(對象后處理器)

一 . 自定義初始化行為和銷毀行為

  Spring.Net 通過幾個專門的接口來控制容器中對象的行為,這些接口包括 Spring.Net 定義的 IInitializingObject接口 和標准的 System.IDisposable 接口。容器會在實現了這兩個接口的對象上調用 AfterPropertyiesSet()方法 和 Dispose()方法,這樣我們就有機會在對象初始化和銷毀時做一些額外的工作。

  通過 Spring.Net 定義的 IInitializingObject接口 可以實現自定義初始化行為。在VS中通過對象瀏覽器我們可以看到 Spring.Objects.Factory.IInitializingObject 接口,只有一個方法:

void AfterPropertiesSet:在對象的所有屬性被設置之后由容器調用。在該方法中,我們可以檢查必需的屬性是否都已被正確設值,或者可以執行進一步的初始化工作。此方法可以拋出任何異常以標識配置錯誤、初始化失敗等情況。

  我們前面討論了如何初始化,接下來我們討論通過標准的 System.IDisposable接口 可以實現自定義銷毀行為。通過 System.IDisposable接口 使我們有機會在容器被銷毀時,通過對象的回調方法來處理容器中對象的銷毀工作。該接口只有一個方法:

void Dispose():當容器被銷毀時調用。在此可釋放對象保留的任何資源(比如數據庫連接)。可在此方法中拋出任何異常,但是此處拋出的任何異常都不會阻止容器的銷毀,只會被記錄到日志中。

來看一下代碼:

 1 using System;
 2 using System.Collections.Generic;
 3 
 4 namespace CnblogLesson_4_5.Model
 5 {
 6     /// <summary>
 7     /// 人類
 8     /// </summary>
 9     public class Person : Spring.Objects.Factory.IInitializingObject , System.IDisposable
10     {
11         public Person() {
12             Console.WriteLine("Person 的構造函數");
13         }
14 
15         public void AfterPropertiesSet()
16         {
17             Console.WriteLine("實現Spring.Objects.Factory.IInitializingObject");
18         }
19 
20 
21         public void Dispose()
22         {
23             Console.WriteLine("實現System.IDisposable接口");
24         }
25     }
26 }

運行程序,看一下結果:

 1 using System;
 2 using Spring.Context;
 3 using Spring.Context.Support;
 4 using CnblogLesson_4_5.Model;
 5 
 6 namespace CnblogLesson_4_5
 7 {
 8     class Program
 9     {
10         static void Main(string[] args)
11         {
12             //通過IApplicationContext來配置
13             IApplicationContext context = ContextRegistry.GetContext();
14             Person hexu = context.GetObject("hexu") as Person;
15 
16             Console.ReadKey();
17         }
18     }
19 }

可以看到  AfterPropertiesSet() 方法在 Person 類的構造函數之后調用。

注意:

  Spring.Net 有一點好處就是,幾乎所有的需求都可以通過配置來完成。一般來說,盡量不要使用 IInitializingObject接口 或 IDisposable接口 。我們可以在XML中配置object 節點的 init-method屬性 或 destroy-method屬性 。配置完成之后,Spring.Net 的 IOC 容器就會幫我們在該對象被實例時調用 init-method 設置的方法 ,在容器被銷毀時調用 destroy-method 設置的方法。

來看一下代碼:

 1 using System;
 2 
 3 namespace CnblogLesson_4_5.Model
 4 {
 5     public class Friend
 6     {
 7         public Friend()
 8         {
 9             Console.WriteLine("Friend 的構造函數");
10         }
11 
12         public void Init()
13         {
14             Console.WriteLine("手動配置init-method=Init");
15         }
16 
17         public void Destroy()
18         {
19             Console.WriteLine("手動配置destroy-method=Destroy");
20         }
21     }
22 }

Objects.xml 配置:

<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">

  <!---手動配置 初始化方法和銷毀方法-->
  <object id="jeery" type="CnblogLesson_4_5.Model.Friend,CnblogLesson_4_5" init-method="Init" destroy-method="Destroy">
    
  </object>
  
</objects>

Program.cs 文件:

 1 using System;
 2 using Spring.Context;
 3 using Spring.Context.Support;
 4 using CnblogLesson_4_5.Model;
 5 
 6 namespace CnblogLesson_4_5
 7 {
 8     class Program
 9     {
10         static void Main(string[] args)
11         {
12             Console.WriteLine("\n\n\n");
13 
14             //通過IApplicationContext來配置
15             IApplicationContext context = ContextRegistry.GetContext();
16             
17             Person hexu = context.GetObject("hexu") as Person;
18             Friend jeery = context.GetObject("jeery") as Friend; 
19             
20             Console.ReadKey();
21         }
22     }
23 }

通過運行程序,可以看到 jeery 對象的 Init 方法被調用:

二 . 抽象對象定義和子對象定義

  在 Spring.Net 對象定義中,對象定義可能會包含大量的信息,比如與容器相關的信息(即初始化方法、靜態工廠方法名等)、構造器參數和屬性值等。也許有很多很多的信息是重復的,這個時候如果我們把每一個定義都寫在配置文件中,那么配置文件就會很大啊。

而根據面向對象的方式,有很多重復的工作,我們可以使用繼承來實現。

好在 Spring.Net 中也幫我們提供了類似繼承這樣的機制。但是 Spring.Net 中這里說的繼承和面向對象的繼承是不一樣的,在這里的繼承不是真正的繼承,它類似設計模式中的模板方法模式,子對象定義是指從一個父對象定義中繼承了配置數據的對象定義。子對象定義可以根據需要重寫或添加某些配置的值。使用父對象和子對象的定義方式可能會節省大量的鍵入工作。子對象和父對象實質上並沒有繼承的關系,只是使用了父對象的一些信息。

在 Spring.NET,子對象定義由 ChildObjectDefintion類 處理。但用戶一般不會直接接觸到該類,仍可使用 XML 對象定義進行配置。在 XML 對象定義中,通過 parent屬性 標識一個對象定義是子對象定義,該屬性的值即為父對象定義的名稱。

來看一下示例代碼:

 1 using System;
 2 using System.Collections.Generic;
 3 
 4 namespace CnblogLesson_4_6.Model
 5 {
 6     /// <summary>
 7     /// Child 類,沒有繼承Parent,它比Parent類多一個Age的屬性
 8     /// </summary>
 9     public class Child
10     {
11         public string Name { get; set; }
12         public int Age { get; set; }
13     }
14 
15 }
 1 using System;
 2 
 3 namespace CnblogLesson_4_6.Model
 4 {
 5     /// <summary>
 6     /// Parent類,為一個抽象類,有一個Name屬性
 7     /// </summary>
 8     public abstract class Parent
 9     {
10         public string Name { get; set; }
11     }
12 
13 }

我們通過常規方式,來裝載對象時,Child 和 Parent 類都需要裝載 Name 屬性。而Spring提供了一種模板方法的方式來配置對象。

配置文件如:

 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <objects xmlns="http://www.springframework.net">
 3 
 4   <!--抽象對象定義和子對象定義-->
 5   <object id="parent" type="CnblogLesson_4_6.Model.Parent, CnblogLesson_4_6" abstract="true">
 6     <property name="Name" value="parent"/>
 7   </object>
 8 
 9   <object id="child" type="CnblogLesson_4_6.Model.Child, CnblogLesson_4_6" parent="parent">
10     <property name="Age" value="18"/>
11   </object>
12 
13 </objects>

通過 parent 我們可以指定 id="child" 的對象,是使用 id="parent" 對象的配置。

通過運行程序,監視變量,我們來看一下,child 和 parent並沒有繼承關系,只是使用了 parent 的配置而已。

  我們可以通過上面的例子看到,沒有在子對象定義中顯式指定的屬性會從父對象定義中繼承值;同時子對象定義也可覆蓋父對象定義的屬性值。這種情況來說,子對象必須與父對象兼容,也就是說,子對象必須能夠接受父對象的屬性值。子對象定義可繼承或覆蓋父對象定義的構造器參數、屬性值及方法,也可以添加新值。如果子對象指定了初始化方法、銷毀方法和/或靜態工廠方法,就會覆蓋父對象定義中的相應配置。

  但是還有一些設置,子對象是不會從父對象繼承過來的。比如:depends-on屬性的值、自動裝配模式、依賴檢查模式、singleton和lazy-init屬性的值等。即子對象定義不會從父對象定義繼承這些屬性,舉例來說,若父對象(抽象)定義了depends-on,而子對象未定義,那么子對象就沒有依賴項。

  如果父對象定義未指定類型...

  比如:

1 <object id="parent">
2     <property name="Name" value="parent"/>
3 </object>

  那么父對象肯定是不能被初始化的,因為它的定義是不完整的。這種定義也被隱式的看作為抽象定義。對象定義也可通過 abstract 屬性顯式指定為抽象定義,該屬性的有效值是 true 或者 false。前面我們對父對象設置過 abstract="true" 屬性,就是一個抽象定義。

  一個抽象的定義僅僅是為用做模版,或者說是作為子對象定義的父對象定義而存在。將對象定義聲明為抽象可防止容器創建該對象。在試圖創建實例化或獲取該對象的時候,系統就拋出 ObjectIsAbstractException 異常。而在 Spring 容器內負責預創建對象的 PreInstantiateSingletons 方法會忽略抽象的對象定義。

  特別要注意的是: IApplicationContext(應用程序上下文) 接口的實現類,而非簡單的對象工廠。在默認情況下會預先創建所有的 singleton 對象。所以,對應用程序上下文來說,下面一點非常重要(至少對於 singleton對象 來說):如果要定義一個僅用做模版的(父)對象定義,而且在該定義中指定了類型,那么就必須保證將其 abstract屬性 設為true,否則應用程序上下文會嘗試預創建這個對象。

  這里寫了太多了,IObjectPostProcessor及擴展類(對象后處理器)就留在下篇寫吧!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM