Spring.Net常被來用來作爲IOC容器和AOP工具,今日有空整理了一下,就個人使用的方法做個總結 ,儘量演示的細一點,大家都能看懂。
實現方式:硬編(代碼實現)和配置表兩種。配置文件的演示一下IOC、AOP、構造函數注入、以及屬性注入。
其他的如方法注入、方法替換、事件注入本次暫不作演示。
本文章涉及的演示實例下載地址:https://download.csdn.net/download/xuefuruanjian/11390775
總結:
1、Spring.Net可以通過接口、抽象類、父類、虛方法進行動態代理
2、可以編程方式也可以使用配置表的方式
3、IOC的時候接口、抽象類、父類、虛方法都可以,但AOP的話,接口、抽象類是沒有問題的,而動態代理父類和類本身的時候,執行方法需要是virtual,纔可以AOP。
實現方式:先以配置表來演示,最後以編程的方式(代碼實現)
一、配置表方式
配置表先放上來,以下4種演示共用這一份配置。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
</configSections>
<spring>
<!--容器配置-->
<context>
<resource uri="config://spring/objects"/>
<!--xml文件方式,更改屬性,複製到輸出目錄:始終複製-->
<!--<resource uri="file://~/Config/objects.xml"/>-->
<!--嵌入程序集方式,assembly://程序集名/項目名/objects.xml,更改屬性,始終複製,生成操作,嵌入的資源-->
<!--<resource uri="assembly://Spring.Net/Spring.Net/objects.xml"/>-->
</context>
<objects xmlns="http://www.springframework.net">
<description>AOP例子</description>
<!--id/name 必須要唯一的,type=類的全名稱,所在的程序集-->
<!--攔截通知-->
<object id="beforeAdvice" type="Spring.Net.Example.Aspects.LogBeforeAdvice,Spring.Net.Example"/>
<object id="aroundAdvice" type="Spring.Net.Example.Aspects.LogAroundAdvice,Spring.Net.Example"/>
<object id="afterAdvice" type="Spring.Net.Example.Aspects.LogAfterAdvice,Spring.Net.Example"/>
<object id="exceptAdvice" type="Spring.Net.Example.Aspects.LogExceptAdvice,Spring.Net.Example"/>
<!--屬性注入-->
<object name="UserInfo" type="Spring.Net.Example.Commands.UserInfo,Spring.Net.Example">
<property name="Name" value="王五"/>
<property name="Age" value="15"/>
</object>
<!--IOC-->
<object id="iocStudentA" type="Spring.Net.Example.Commands.StudentA,Spring.Net.Example" />
<object id="iocStudentB" type="Spring.Net.Example.Commands.StudentB,Spring.Net.Example" />
<object id="iocStudentC" type="Spring.Net.Example.Commands.StudentC,Spring.Net.Example" />
<object id="iocStudentD" type="Spring.Net.Example.Commands.StudentD,Spring.Net.Example" />
<!--AOP-->
<object id="aopStudentA" type="Spring.Aop.Framework.ProxyFactoryObject">
<property name="Target">
<object type="Spring.Net.Example.Commands.StudentA, Spring.Net.Example" />
</property>
<property name="InterceptorNames">
<list>
<value>beforeAdvice</value>
<value>aroundAdvice</value>
<value>afterAdvice</value>
<value>exceptAdvice</value>
</list>
</property>
</object>
<object id="aopStudentB" type="Spring.Aop.Framework.ProxyFactoryObject">
<property name="Target">
<object type="Spring.Net.Example.Commands.StudentB, Spring.Net.Example" />
</property>
<property name="InterceptorNames">
<list>
<value>beforeAdvice</value>
<value>aroundAdvice</value>
<value>afterAdvice</value>
<value>exceptAdvice</value>
</list>
</property>
</object>
<object id="aopStudentC" type="Spring.Aop.Framework.ProxyFactoryObject">
<property name="Target">
<object type="Spring.Net.Example.Commands.StudentC, Spring.Net.Example" />
</property>
<property name="InterceptorNames">
<list>
<value>beforeAdvice</value>
<value>aroundAdvice</value>
<value>afterAdvice</value>
<value>exceptAdvice</value>
</list>
</property>
</object>
<object id="aopStudentD" type="Spring.Aop.Framework.ProxyFactoryObject">
<property name="Target">
<object type="Spring.Net.Example.Commands.StudentD, Spring.Net.Example" />
</property>
<property name="InterceptorNames">
<list>
<value>beforeAdvice</value>
<value>aroundAdvice</value>
<value>afterAdvice</value>
<value>exceptAdvice</value>
</list>
</property>
</object>
<!--屬性注入-->
<object id="attrStudentA" type="Spring.Net.Example.Commands.StudentA,Spring.Net.Example">
<!--ref指向下面的屬性注入-->
<property name="Friend" ref="UserInfo" />
<!--<property name="Friend">
<object type="Spring.Net.Example.Commands.UserInfo,Spring.Net.Example">
<property name="Name" value="王五"/>
<property name="Age" value="15"/>
</object>
</property>-->
</object>
<object id="attrStudentB" type="Spring.Net.Example.Commands.StudentB,Spring.Net.Example">
<!--ref指向下面的屬性注入-->
<property name="Friend" ref="UserInfo" />
</object>
<object id="attrStudentC" type="Spring.Net.Example.Commands.StudentC,Spring.Net.Example">
<property name="Friend" ref="UserInfo" />
</object>
<object id="attrStudentD" type="Spring.Net.Example.Commands.StudentD,Spring.Net.Example">
<property name="Friend" ref="UserInfo" />
</object>
<!--構造函數注入-->
<!--autowire="constructor"根據構造函數注入 au-->
<object id="constructorStudentE" type="Spring.Net.Example.Commands.StudentE,Spring.Net.Example">
<!--<constructor-arg value="李四" type="string" index="0"/>
<constructor-arg value="19" type="int" index="1"/>-->
<constructor-arg index="2" ref="UserInfo"/>
<constructor-arg index="1" type="int">
<value><![CDATA[19]]></value>
</constructor-arg>
<constructor-arg index="0">
<value><![CDATA[李四]]></value>
</constructor-arg>
</object>
<object id="constructorStudentF" type="Spring.Net.Example.Commands.StudentF,Spring.Net.Example">
<constructor-arg value="李四" type="string" index="0"/>
<constructor-arg value="19" type="int" index="1"/>
<constructor-arg index="2" ref="UserInfo"/>
</object>
<object id="constructorStudentG" type="Spring.Net.Example.Commands.StudentG,Spring.Net.Example">
<constructor-arg value="李四" type="string" index="0"/>
<constructor-arg value="19" type="int" index="1"/>
<constructor-arg index="2" ref="UserInfo"/>
</object>
<object id="constructorStudentH" type="Spring.Net.Example.Commands.StudentH,Spring.Net.Example">
<constructor-arg value="李四" type="string" index="0"/>
<constructor-arg value="19" type="int" index="1"/>
<constructor-arg index="2" ref="UserInfo"/>
</object>
</objects>
</spring>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
攔截通知類(AOP使用)
namespace Spring.Net.Example.Aspects
{
public class LogBeforeAdvice : IMethodBeforeAdvice
{
public void Before(MethodInfo method, object[] args, object target)
{
Console.WriteLine("[執行前通知]攔截的方法名—>" + method.Name);
Console.WriteLine("[執行前通知]目標—>" + target);
Console.WriteLine("[執行前通知]參數—>");
if (args != null)
{
foreach (object arg in args)
{
Console.WriteLine("\t: " + arg);
}
}
}
}
public class LogAroundAdvice : IMethodInterceptor
{
public object Invoke(IMethodInvocation invocation)
{
Console.Out.WriteLine(String.Format("[環繞通知]攔截的方法名—> '{0}'", invocation.Method.Name));
object returnValue = invocation.Proceed();
Console.Out.WriteLine(String.Format("[環繞通知]返回—> '{0}'", returnValue));
return returnValue;
}
}
public class LogAfterAdvice : IAfterReturningAdvice
{
public void AfterReturning(object returnValue, MethodInfo method, object[] args, object target)
{
Console.Out.WriteLine("[執行後通知]攔截的方法名—>" + method.Name);
Console.Out.WriteLine("[執行後通知]目標—>" + target);
Console.Out.WriteLine("[執行後通知]參數—>");
if (args != null)
{
foreach (object arg in args)
{
Console.Out.WriteLine("\t: " + arg);
}
}
Console.Out.WriteLine("[執行後通知]返回值—>" + returnValue);
}
}
public class LogExceptAdvice : IThrowsAdvice
{
public void AfterThrowing(Exception ex)
{
Console.Error.WriteLine($"異常—>{ex.Message}");
}
}
}
四個演示所用的接口、抽象類、父類
namespace Spring.Net.Example.Commands
{
public interface IStudent
{
UserInfo Friend { get; set; }
string Name { get; set; }
int Age { get; set; }
void Show();
}
public class BaseStudent
{
public UserInfo Friend { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public void Run()
{
Console.WriteLine($"我是父類裏的方法,名字{this.Name},年齡{this.Age}");
if (this.Friend != null)
Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
}
}
public abstract class AbstractStudent
{
public abstract void Read();
}
}
第1、2、3個示例使用的實體類
namespace Spring.Net.Example.Commands
{
public class StudentA
{
public UserInfo Friend { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public void Show()
{
Console.WriteLine($"我是類裏的方法,名字{this.Name},年齡{this.Age}");
if (this.Friend != null)
Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
}
}
public class StudentB : BaseStudent
{
public void Show()
{
Console.WriteLine($"我是{this.Name},年齡{this.Age}");
if (this.Friend != null)
Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
}
}
public class StudentC : AbstractStudent
{
public UserInfo Friend { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public void Show()
{
Console.WriteLine($"我是{this.Name},年齡{this.Age}");
if (this.Friend != null)
Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
}
public override void Read()
{
Console.WriteLine($"我是抽象類的重載,名字{this.Name},年齡{this.Age}");
if (this.Friend != null)
Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
}
}
public class StudentD : IStudent
{
public UserInfo Friend { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public void Show()
{
Console.WriteLine($"我實現了接口的方法,名字{this.Name},年齡{this.Age}");
if (this.Friend != null)
Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
}
}
}
1、IOC容器
接口、抽象類、父類、類IOC實例化實現方式基本一致,配置參考配置表IOC部分,以下爲示例
static void Main(string[] args)
{
//****************IOC***************************
IApplicationContext context = ContextRegistry.GetContext();
//實例化類(StudentA可以繼承也可以不繼承都可以實例化)
StudentA selfCommand = (StudentA)context["iocStudentA"];
//StudentB selfCommand = (StudentB)context["iocStudentB"];
//StudentC selfCommand = (StudentC)context["iocStudentC"];
//StudentD selfCommand = (StudentD)context["iocStudentD"];
selfCommand.Show();
Console.WriteLine("--------");
//實例化父類(StudentB繼承BaseStudent)
BaseStudent parentCommand = (BaseStudent)context["iocStudentB"];
parentCommand.Run();
Console.WriteLine("--------");
//實例化基類(StudentC繼承AbstractStudent)
AbstractStudent abstractCommand = (AbstractStudent)context["iocStudentC"];
abstractCommand.Read();
Console.WriteLine("--------");
//實例化接口(StudentD實現接口IStudent)
IStudent interfaceCommand = (IStudent)context["iocStudentD"];
interfaceCommand.Show();
Console.ReadLine();
}
執行結果:
2、實現AOP
通知類在文章的開頭貼出爲了,請參考,配置參考配置表中AOP部分。
特別提醒:
1、Spring.Net爲了不破壞了OO的封裝性,所以沒有實現對字段攔截的支持。
2、代理接口之外的其他代理,如代理類,是隻有虛方法才能代理,同理屬性也是如此,只有virtual的屬性纔可以注入。如果發現已經在配置中配置了構造注入或屬性注入,而得到的代理對象(如下面調用的selfCommand)中,屬性還爲空的話,就要檢查屬性是不是沒有virtual了。
3、建議按編程規範,類都實現接口,代理接口最方便。
上層調用如下:
class Program
{
static void Main(string[] args)
{
//*****************AOP********************************
IApplicationContext context = ContextRegistry.GetContext();
//實例化類
//執行方法爲虛方法時可以AOP
StudentA selfCommand = (StudentA)context["aopStudentA"];
//StudentB selfCommand = (StudentB)context["aopStudentB"];
//StudentC selfCommand = (StudentC)context["aopStudentC"];
//實現了接口的類,不能被代理類本身,可以代理爲接口,如下面第四個(IStudent)context["aopStudentD"]
//StudentD selfCommand = (StudentD)context["aopStudentD"]; //異常
selfCommand.Show();
Console.WriteLine("--------");
//實例化父類(StudentB繼承BaseStudent)
//執行方法爲虛方法時可以AOP
BaseStudent parentCommand = (BaseStudent)context["aopStudentB"];
parentCommand.Run();
Console.WriteLine("--------");
//實例化基類(StudentC繼承AbstractStudent)
AbstractStudent abstractCommand = (AbstractStudent)context["aopStudentC"];
abstractCommand.Read();
Console.WriteLine("--------");
//實例化接口(StudentD實現接口IStudent)
IStudent interfaceCommand = (IStudent)context["aopStudentD"];
interfaceCommand.Show();
Console.ReadLine();
}
}
執行結果
看結果:
AOP的時候,實例化爲(AbstractStudent)context["aopStudentC"]和 (IStudent)context["aopStudentD"]的時候,實現了AOP,而(BaseStudent)context["aopStudentB"] 和實例化成類本身(StudentA)context["aopStudentA"],只執行了方法本身,沒有實現AOP。這是爲什麼呢?是因爲執行的方法都不是虛方法(StudentA.Show()和BaseStudent.Run()),如下:
public class StudentA
{
public UserInfo Friend { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public void Show()
{
Console.WriteLine($"我是類裏的方法,名字{this.Name},年齡{this.Age}");
if (this.Friend != null)
Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
}
}
public class BaseStudent
{
public UserInfo Friend { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public void Run()
{
Console.WriteLine($"我是父類裏的方法,名字{this.Name},年齡{this.Age}");
if (this.Friend != null)
Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
}
}
動態代理類或父類,需要執行方法是virtual纔可以AOP(StudentA.Show()和BaseStudent.Run()),現把兩個方法改爲如下:
public class StudentA
{
public UserInfo Friend { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public virtual void Show()
{
Console.WriteLine($"我是類裏的方法,名字{this.Name},年齡{this.Age}");
if (this.Friend != null)
Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
}
}
public class BaseStudent
{
public UserInfo Friend { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public virtual void Run()
{
Console.WriteLine($"我是父類裏的方法,名字{this.Name},年齡{this.Age}");
if (this.Friend != null)
Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
}
}
結果:
這樣都實現了AOP。
AOP的配置屬性也羅列一下,供大家參考:
-
ProxyTargetType:布爾類型,如果目標類是被直接代理的,該屬性爲true;反之則只代理目標類所實現的接口(比如代理某個由接口定義的方法)。(按:目前默認的方式是代理接口)
-
Optimize:是否使用強制優化(aggressive optimization)來創建代理。除非很清楚相關的AOP代理是如何處理優化的,否則不要將其設爲true。這個屬性的確切含義會隨代理的實現方式不同而不盡相同,並且,強制優化通常是對代理的創建時間和運行性能的折衷。優化可能被某些代理實現類所忽略,也可能因其它屬性的某些值而被禁用(在後臺被禁用,不會有任何形式的通知),如ExposeProxy屬性等。
-
IsFrozen:代理工廠配置完成後是否允許改變通知。默認值爲false。
-
ExposeProxy:是否通過AopContext暴露當前代理,以便目標對象能夠訪問自己的代理對象。(若不使用AopContext則可通過IMethodInvocation接口獲得當前代理的引用)如果目標對象需要引用代理,並且ExposeProxy屬性的值爲true,那麼目標對象就可通過AopContext.CurrentProxy屬性獲取當前代理的引用。
-
AopProxyFactory:在生成代理時要使用的IAopProxyFactory實現類。該屬性允許我們選擇AOP代理對象的創建策略:是使用遠程代理還是動態生成IL,或是其它的方式,默認的實現類會使用動態生成IL的方式來創建基於對象組合的代理。
其它屬性包括:
-
ProxyInterfaces:一個字符串數組,用於保存要代理的接口名。(按:即目標類所實現的某個或某些接口。SDK參考文檔上該屬性的類型是void,是錯的)
-
InterceptorNames:一個字符串數組,保存要應用的IAdvisor、攔截器或其它通知的名稱。其中的順序很重要,排在前面的會先處理(按:使用編程方式時,”排在前面“是指後使用AddAdvice方法加入的攔截器)。列表中第一個攔截器會第一個攔截目標調用(當然如果它是MethodInterceptor或BeforeAdvice時)。名稱所指向的對象必須定義在當前容器或父容器中。這裏不能直接引用對象定義,否則IsSingleton屬性就沒有意義了。
-
IntroductionNames:引入通知對象定義的名稱列表。如果某個名稱指向的對象沒有實現IIntroductionAdvisor接口,AOP框架就會創建一個DefaultIntroductionAdvisor的實例並將該名稱分配給這個實例,這樣,引入通知對象的所有方法都會被添加到目標對象中去。如果使用實現了IIntroductionAdvisor的類,就可以精確的控制要引入的接口。
-
IsSingleton:表示工廠是否要返回唯一的代理對象,而不管GetObject方法被調用多少次(部分IFactoryObject的實現類提供了這個方法)。默認值是true。如果要應用基於實例的通知,就要將該屬性設爲false,且IsFrozen屬性也應該爲false。如果需要使用有狀態的通知——例如一個有狀態的、prototype模式的引入通知——就可以將該屬性設爲false。
另外需要說明的話是:實現了接口的類,不能被代理成類本身的類型,可以代理爲接口(IStudent)context["aopStudentD"]
IApplicationContext context = ContextRegistry.GetContext();
//StudentA selfCommand = (StudentA)context["aopStudentA"]; //正常
//StudentB selfCommand = (StudentB)context["aopStudentB"]; //正常
//StudentC selfCommand = (StudentC)context["aopStudentC"]; //正常
//StudentD實現接口IStudent
StudentD selfCommand = (StudentD)context["aopStudentD"]; //異常
IStudent interfaceCommand = (IStudent)context["aopStudentD"]; //正常
創建了對象,如果是簡單對象就到此爲止,如果是複雜對象,則需要爲它的屬性賦值。
屬性賦值有兩種方法:屬性注入和構造器注入。
3、屬性注入
class Program
{
static void Main(string[] args)
{
//*****************屬性注入********************************
IApplicationContext context = ContextRegistry.GetContext();
//實例化類
StudentA selfCommand = (StudentA)context["attrStudentA"];
selfCommand.Show();
Console.WriteLine("--------");
//實例化父類(StudentB繼承BaseStudent)
BaseStudent parentCommand = (BaseStudent)context["attrStudentB"];
parentCommand.Run();
Console.WriteLine("--------");
//實例化基類(StudentC繼承AbstractStudent)
AbstractStudent abstractCommand = (AbstractStudent)context["attrStudentC"];
abstractCommand.Read();
Console.WriteLine("--------");
//實例化接口(StudentD實現接口IStudent)
IStudent interfaceCommand = (IStudent)context["attrStudentD"];
interfaceCommand.Show();
Console.ReadLine();
}
}
結果:
這裏主要演示屬性注入,不管是代理類、接口、抽象類、父類都生效。配置如下:
<!--聲明-->
<object name="UserInfo" type="Spring.Net.Example.Commands.UserInfo,Spring.Net.Example">
<property name="Name" value="王五"/>
<property name="Age" value="15"/>
</object>
<object id="attrStudentB" type="Spring.Net.Example.Commands.StudentB,Spring.Net.Example">
<!--ref指向下面的屬性注入-->
<property name="Friend" ref="UserInfo" />
</object>
配置還有一種寫法,把引用對象直接寫在屬性下面,如下:
<object id="attrStudentB" type="Spring.Net.Example.Commands.StudentB,Spring.Net.Example">
<!--ref指向下面的屬性注入-->
<!--<property name="Friend" ref="UserInfo" />-->
<property name="Friend">
<object type="Spring.Net.Example.Commands.UserInfo,Spring.Net.Example">
<property name="Name" value="王五"/>
<property name="Age" value="15"/>
</object>
</property>
</object>
4、構造函數注入
當默認的無參構造函數不存在,構造函數需要參數的時候,怎麼辦呢,可以在配置文件裏進行配置。
接口類、抽象類、父類繼續使用文章開頭貼出來的類,實體類和上層調用方法如下:
namespace Spring.Net.Example.Commands
{
public class StudentE
{
public StudentE(string name, int age, UserInfo friend)
{
Name = name;
Age = age;
Friend = friend;
}
public UserInfo Friend { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public void Show()
{
Console.WriteLine($"我是類裏的方法,名字{this.Name},年齡{this.Age}");
if (this.Friend != null)
Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
}
}
public class StudentF : BaseStudent
{
public StudentF(string name, int age, UserInfo friend)
{
Name = name;
Age = age;
Friend = friend;
}
public void Show()
{
Console.WriteLine($"我是{this.Name},年齡{this.Age}");
if (this.Friend != null)
Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
}
}
public class StudentG : AbstractStudent
{
public StudentG(string name, int age, UserInfo friend)
{
Name = name;
Age = age;
Friend = friend;
}
public UserInfo Friend { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public void Show()
{
Console.WriteLine($"我是{this.Name},年齡{this.Age}");
if (this.Friend != null)
Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
}
public override void Read()
{
Console.WriteLine($"我是抽象類的重載,名字{this.Name},年齡{this.Age}");
if (this.Friend != null)
Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
}
}
public class StudentH : IStudent
{
public StudentH(string name, int age, UserInfo friend)
{
Name = name;
Age = age;
Friend = friend;
}
public UserInfo Friend { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public void Show()
{
Console.WriteLine($"我是{this.Name},年齡{this.Age}");
if (this.Friend != null)
Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
}
}
}
class Program
{
static void Main(string[] args)
{
//*****************構造函數注入********************************
IApplicationContext context = ContextRegistry.GetContext();
//實例化類
StudentE selfCommand = (StudentE)context["constructorStudentE"];
selfCommand.Show();
Console.WriteLine("--------");
//實例化父類(StudentF繼承BaseStudent)
BaseStudent parentCommand = (BaseStudent)context["constructorStudentF"];
parentCommand.Run();
Console.WriteLine("--------");
//實例化基類(StudentG繼承AbstractStudent)
AbstractStudent abstractCommand = (AbstractStudent)context["constructorStudentG"];
abstractCommand.Read();
Console.WriteLine("--------");
//實例化接口(StudentH實現接口IStudent)
IStudent interfaceCommand = (IStudent)context["constructorStudentH"];
interfaceCommand.Show();
Console.ReadLine();
}
}
結果爲:
這裏主要說明構造函數的參數注入,不管是代理類、接口、抽象類、父類都生效。
<object name="UserInfo" type="Spring.Net.Example.Commands.UserInfo,Spring.Net.Example">
<property name="Name" value="王五"/>
<property name="Age" value="15"/>
</object>
<object id="constructorStudentF" type="Spring.Net.Example.Commands.StudentF,Spring.Net.Example">
<constructor-arg value="李四" type="string" index="0"/>
<constructor-arg value="19" type="int" index="1"/>
<constructor-arg index="2" ref="UserInfo"/>
</object>
constructor-arg 有value、type、index三個參數,其中index是參數的序號,以0開始。type、index有時也可以省略。
內聯類型則需要同過ref屬性來設置,先配置映射,然後用ref引用。
構造函數參數解析有三種方法:
1)根據參數類型匹配(type)
<constructor-arg type="string" value="李四" />
<constructor-arg type="int" value="19" />
2)根據參數索引匹配(index)
<constructor-arg index="0" value="李四" />
<constructor-arg index="1" value="19" />
3)根據參數名稱匹配(name)
<constructor-arg name="name" value="李四" />
<constructor-arg name="age" value="19" />
當然也可以混着用
有時候參數裏有特殊字符,也可以換個寫法,使用<![CDATA[]]>,type、index有時也可以省略。
<object name="UserInfo" type="Spring.Net.Example.Commands.UserInfo,Spring.Net.Example">
<property name="Name" value="王五"/>
<property name="Age" value="15"/>
</object>
<object id="constructorStudentF" type="Spring.Net.Example.Commands.StudentF,Spring.Net.Example">
<constructor-arg index="1" type="int">
<value><![CDATA[19]]></value>
</constructor-arg>
<constructor-arg index="0">
<value><![CDATA[李四]]></value>
</constructor-arg>
<constructor-arg index="2" ref="UserInfo"/>
</object>
如果有AOP攔截的時候,可以寫在Target的對象映射裏
<object name="UserInfo" type="Spring.Net.Example.Commands.UserInfo,Spring.Net.Example">
<property name="Name" value="王五"/>
<property name="Age" value="15"/>
</object>
<object id="constructorStudentF" type="Spring.Aop.Framework.ProxyFactoryObject">
<property name="Target">
<object type="Spring.Net.Example.Commands.StudentF, Spring.Net.Example">
<constructor-arg value="張三" type="string" index="0"/>
<constructor-arg value="20" type="int" index="1"/>
<constructor-arg index="2" ref="UserInfo"/>
<!--<constructor-arg>
<value><![CDATA[李四]]></value>
</constructor-arg>
<constructor-arg>
<value><![CDATA[19]]></value>
</constructor-arg>-->
</object>
</property>
<property name="InterceptorNames">
<list>
<value>beforeAdvice</value>
<value>aroundAdvice</value>
<value>afterAdvice</value>
<value>exceptAdvice</value>
</list>
</property>
</object>
實現方式,直接編程
不需要配置表,直接硬編,也可以實現。AOP的話,父類代理或者類的代理需要把執行方法改爲virtual,要不沒有AOP。
namespace Spring.Net.Example.Commands
{
public class StudentD : IStudent
{
public UserInfo Friend { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public void Show()
{
Console.WriteLine($"我實現了接口的方法,名字{this.Name},年齡{this.Age}");
if (this.Friend != null)
Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
}
}
}
class Program
{
static void Main(string[] args)
{
//*****************編程式--硬編********************************
ProxyFactory factory = new ProxyFactory(new StudentD());
factory.AddAdvice(new LogBeforeAdvice());
factory.AddAdvice(new LogAfterAdvice());
factory.AddAdvice(new LogExceptAdvice());
IStudent command = (IStudent)factory.GetProxy();
command.Show();
Console.ReadLine();
}
}