多數使用者都會將容器中的大部分對象布署為singleton模式。當一個singleton對象需要和另一個singleton對象協作,或者一個非singleton對象需要和另一個非singleson對象協作時,Spring.NET都能很好的處理它們的依賴關係。但是,如果對象的生存周期不同,就可能會產生問題。例如,假設一個singleton對象A要使用一個非singleton(原型)對象B,A中的每個方法都會用到B的新執行個體。由於A是singleton對象,容器只有會建立它一次,也就是說只有一次給A的屬性賦值的機會,所以不可能在每次A需要的時候都給它注入一個新的B。
有一種解決的辦法有點違背控制反轉原則:類A可以通過實現IObjectFactoryAware{
tagshow(event)
}">介面來擷取容器的引用,並調用GetObject("B")在每次需要的時候從容器中請求一個(新的)對象B。但這並不是一個很好的解決方案,因為客戶代碼此時必須要和Spring.NET發生緊耦合。
通過方法注入,我們可以用更優雅的方式解決類似的問題。(摘自Spring.NET中文手冊)
一、查詢方法注入
Spring.NET可以動態覆蓋對象的抽象方法或虛方法,並且可以在容器內尋找已命名物件,查詢方法注入就利用了這些功能。個人感覺查詢方法注入類似抽象工廠,為之不同的是,可以不用寫抽象的實現代碼,通過{
tagshow(event)
}">設定檔動態切換{
tagshow(event)
}">組件。
在lookup-method節點配置name和object屬性
實現代碼如下:
- <!--查詢方法-->
- <object id="personDao" type="SpringNet_MethodDi.PersonDao, SpringNet_MethodDi" singleton="false"/>
- <object id="objectFactory" type="SpringNet_MethodDi.ObjectFactory, SpringNet_MethodDi">
- <lookup-method name="CreatePersonDao" object="personDao"/>
- </object>
複製代碼
LookupMethod
- //注意,可以直接在配置中定義這個類的對象
- public abstract class ObjectFactory
- {
- //或者可以是一個虛方法
- public abstract PersonDao CreatePersonDao();
- }
- public class PersonDao
- {
- public void Save()
- {
- Console.WriteLine("儲存資料");
- }
- }
複製代碼
二、替換任意方法
替換任意方法在項目中使用的很少,實現方法也比較複雜。至於Spring.NET為什麼使用替換任意方法,我還不是很清楚,如果有知道使用情境的朋友可以給我留言。我個人認為其用途是:實現非衍生類別方法的重寫或在IoC架構中簡易的AOP攔截(這一點又不確定,以後我會寫AOP方面的部落格)。
首先繼承IMethodReplacer介面並實現Implement方法,object[] arguments為傳入的參數。其次在replaced-method節點配置name和replacer屬性,和增加arg-type節點且配置傳回型別match屬性
代碼如下:
- <!--替換方法-->
- <object id="userDao" type="SpringNet_MethodDi.UserDao, SpringNet_MethodDi">
- <replaced-method name="GetValue" replacer="replaceValue">
- <arg-type match="String"/>
- </replaced-method>
- </object>
- <object id="replaceValue" type="SpringNet_MethodDi.ReplaceValue, SpringNet_MethodDi"/>
複製代碼
ReplacedMethod
- public class UserDao
- {
- //虛方法
- public virtual string GetValue(string input)
- {
- return null;
- }
- }
- //實現IMethodReplacer介面
- public class ReplaceValue : IMethodReplacer
- {
- public object Implement(object target, MethodInfo method, object[] arguments)
- {
- string value = (string)arguments[0];
- return "擷取到:" + value;
- }
- }
複製代碼三、事件注入
在Spring.NET的IoC架構中,除了提供方法注入以外,還提供事件的注入。通過事件的注入,可以使架構體系的耦合降到最低。(參考 clingingboy的 Spring.NET學習筆記(3)-註冊事件注入)
在listener節點處配置event和method屬性指明事件名和綁定的方法,並增加ref節點設定object屬性來指明調用哪個IoC容器物件。
實現代碼:
- <!--事件注入-->
- <object id="men" type="SpringNet_MethodDi.Men, SpringNet_MethodDi">
- <listener event="OpenTheDoor" method="OpenThisDoor">
- <ref object="door"/>
- </listener>
- </object>
- <object id="door" type="SpringNet_MethodDi.Door, SpringNet_MethodDi" />
複製代碼
Listener
- //先定義一個委託
- public delegate string OpenHandler(string arg);
- public class Door
- {
- public event OpenHandler OpenTheDoor;
- public void OnOpen(string arg)
- {
- //呼叫事件
- if (OpenTheDoor != null)
- {
- Console.WriteLine(OpenTheDoor(arg));
- }
- }
- }
- public class Men
- {
- public string OpenThisDoor(string arg)
- {
- return "參數是:" + arg;
- }
- }
複製代碼
調用部分代碼:
Program
- class Program
- {
- static void Main(string[] args)
- {
- IApplicationContext ctx = ContextRegistry.GetContext();
- Console.WriteLine("查詢方法");
- ObjectFactory factory = (ObjectFactory)ctx.GetObject("objectFactory");
- factory.CreatePersonDao().Save();
- Console.WriteLine();
- Console.WriteLine("替換方法");
- UserDao dao = (UserDao)ctx.GetObject("userDao");
- Console.WriteLine(dao.GetValue("Liu Dong"));
- Console.WriteLine();
- Console.WriteLine("事件註冊");
- Door door = (Door)ctx.GetObject("door");
- door.OnOpen("Opening!");
- Console.WriteLine();
- Console.ReadLine();
- }
- }
複製代碼
輸入效果: