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();
}
}