[Spring.NET IoC] 之一:基本信息
作者:Q.yuhen 来源:Q.yuhen
Spring.NET 移植自著名的 Java 开源项目 —— Spring,借助于 .NET 强大的反射机制,甚至拥有比原 Java 版本更强大的功能。只是不知道什么原因,在 .NET 领域似乎没有多少热度,其影响力甚至不如 Castle。因准备在个人项目中使用 IoC,因此花些时间对 Spring.NET 和 Castle 都作一些了解,本文权作学习笔记。
作者:Q.yuhen 来源:Q.yuhen
Spring.NET 移植自著名的 Java 开源项目 —— Spring,借助于 .NET 强大的反射机制,甚至拥有比原 Java 版本更强大的功能。只是不知道什么原因,在 .NET 领域似乎没有多少热度,其影响力甚至不如 Castle。因准备在个人项目中使用 IoC,因此花些时间对 Spring.NET 和 Castle 都作一些了解,本文权作学习笔记。
Spring.NET 的宣传口号中有 "non-invasiveness. Quite simply" 的字样,表示是非入侵且易用的,当然作为一个IoC容器,这些都是最基本的特征。
在 Spring.NET IoC 中最核心的内容应该是 IObjectFactory、IApplicationContext、IObjectDefinition 这三个接口了。IObjectFactory 是核心容器接口,负责管理容器内的注入对象,而 IApplicationContext 则是 IObjectFactory 的继承,它扩展了一些功能。IObjectDefinition 是注入对象的定义接口,供 IObjectFactory / IApplicationContext 调用。
大多数时候我们会选择 IApplicationContext 接口的实现类来操控 Spring.NET IoC 容器。
1. Spring.Context.Support.ContextRegistry
将配置信息写入 app.config / web.config 时所使用该类。
将配置信息写入 app.config / web.config 时所使用该类。
2. Spring.Context.Support.XmlApplicationContext
使用独立的 xml 配置文件,或者使用多个 xml 配置文件时,使用该类。
使用独立的 xml 配置文件,或者使用多个 xml 配置文件时,使用该类。
3. Spring.Context.Support.StaticApplicationContext
直接在代码中装配容器时,使用该类。
直接在代码中装配容器时,使用该类。
当然,你还可以使用 Spring.Objects.Factory.Xml.XmlObjectFactory 等直接实现 IObjectFactory 的类型。
作为该篇的结束,写一个简单的 "Hello World" 尝试一下。
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Spring.Core;
using Spring.Context;
using Spring.Context.Support;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Spring.Core;
using Spring.Context;
using Spring.Context.Support;
namespace ConsoleApplication1.SpringNet
{
public class HelloWorld
{
public override string ToString()
{
return "Hello, World!";
}
}
{
public class HelloWorld
{
public override string ToString()
{
return "Hello, World!";
}
}
public class Program
{
static void Main(string[] args)
{
StaticApplicationContext context = new StaticApplicationContext();
context.RegisterPrototype("HelloWorld", typeof(HelloWorld), null);
{
static void Main(string[] args)
{
StaticApplicationContext context = new StaticApplicationContext();
context.RegisterPrototype("HelloWorld", typeof(HelloWorld), null);
object o = context.GetObject("HelloWorld");
Console.WriteLine(o);
}
}
}
[Spring.NET IoC] 之二:配置文件
Spring.NET IoC 支持2种配置文件方式:
Console.WriteLine(o);
}
}
}
[Spring.NET IoC] 之二:配置文件
Spring.NET IoC 支持2种配置文件方式:
1. 应用程序配置文件
app.config / web.config
test.cs
IApplicationContext context = ContextRegistry.GetContext();
object o = context.GetObject("HelloWorld");
IApplicationContext context = ContextRegistry.GetContext();
object o = context.GetObject("HelloWorld");
2. 独立配置文件
springtest.xml
http://www.springframework.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
test.cs
IApplicationContext context = new XmlApplicationContext(@"springtest.xml");
object o = context.GetObject("HelloWorld");
IApplicationContext context = new XmlApplicationContext(@"springtest.xml");
object o = context.GetObject("HelloWorld");
建议使用独立的配置文件,应用程序配置文件已经被塞入太多内容了。Spring.NET 还支持很多高级的
[Spring.NET IoC] 之三:获取对象
依照第二篇的配置文件,我们可以初步注入我们所需的类型。本篇将记录获取对象的不同方法。
[Spring.NET IoC] 之三:获取对象
依照第二篇的配置文件,我们可以初步注入我们所需的类型。本篇将记录获取对象的不同方法。
1. 构造方法创建对象
这种方式最常见,大多数时候我们都会采取此方式获取对象。如果目标对象需要提供构造参数,我们也可以在配置文件中提供。
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Spring.Core;
using Spring.Context;
using Spring.Context.Support;
namespace ConsoleApplication1.SpringNet
{
public class HelloWorld
{
private string name;
private int age;
{
public class HelloWorld
{
private string name;
private int age;
public HelloWorld(string name, int age)
{
this.name = name;
this.age = age;
}
{
this.name = name;
this.age = age;
}
public override string ToString()
{
return String.Format("Name={0}; Age={1}", name, age);
}
}
{
return String.Format("Name={0}; Age={1}", name, age);
}
}
public class Program
{
static void Main(string[] args)
{
IApplicationContext context = new XmlApplicationContext(@"Config\Spring.xml");
object o = context.GetObject("HelloWorld");
Console.WriteLine(o);
}
}
}
{
static void Main(string[] args)
{
IApplicationContext context = new XmlApplicationContext(@"Config\Spring.xml");
object o = context.GetObject("HelloWorld");
Console.WriteLine(o);
}
}
}
需要注意的是 Spring.NET IoC 缺省对象创建方式是 "Singleton",我们写个例子验证一下。
object o = context.GetObject("HelloWorld");
object o2 = context.GetObject("HelloWorld");
Console.WriteLine(object.ReferenceEquals(o, o2)); // output: true
object o2 = context.GetObject("HelloWorld");
Console.WriteLine(object.ReferenceEquals(o, o2)); // output: true
我们只需在配置文件中添加一个标记即可改变为非 Singleton 方式。
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
2. 静态工厂方法创建对象
我们提供另外一个 HelloWorld 类,该类型没有公用构造方法,只能通过静态方法创建对象。
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Spring.Core;
using Spring.Context;
using Spring.Context.Support;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Spring.Core;
using Spring.Context;
using Spring.Context.Support;
namespace ConsoleApplication1.SpringNet
{
public class HelloWorld
{
private HelloWorld()
{
}
{
public class HelloWorld
{
private HelloWorld()
{
}
public static HelloWorld Create()
{
return new HelloWorld();
}
}
{
return new HelloWorld();
}
}
public class Program
{
static void Main()
{
IApplicationContext context = new XmlApplicationContext(@"Config\Spring.xml");
{
static void Main()
{
IApplicationContext context = new XmlApplicationContext(@"Config\Spring.xml");
object o = context.GetObject("HelloWorld");
object o2 = context.GetObject("HelloWorld");
Console.WriteLine(object.ReferenceEquals(o, o2)); // output: true
}
}
}
object o2 = context.GetObject("HelloWorld");
Console.WriteLine(object.ReferenceEquals(o, o2)); // output: true
}
}
}
对于这种方式,我们只需指定 "factory-method" 即可,需要注意的是所指定的方法必须是静态方法。
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
3. 实例工厂方法创建对象
修改上面的例子。在下面的代码中我们必须通过一个名为 Creator 的类才能创建 HelloWorld。
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Spring.Core;
using Spring.Context;
using Spring.Context.Support;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Spring.Core;
using Spring.Context;
using Spring.Context.Support;
namespace ConsoleApplication1.SpringNet
{
public class Creator
{
public HelloWorld Create()
{
return new HelloWorld();
}
}
{
public class Creator
{
public HelloWorld Create()
{
return new HelloWorld();
}
}
public class HelloWorld
{
internal HelloWorld()
{
}
}
{
internal HelloWorld()
{
}
}
public class Program
{
static void Main()
{
IApplicationContext context = new XmlApplicationContext(@"Config\Spring.xml");
object o = context.GetObject("HelloWorld");
object o2 = context.GetObject("HelloWorld");
Console.WriteLine(object.ReferenceEquals(o, o2)); // output: true
}
}
}
http://www.springframework.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
{
static void Main()
{
IApplicationContext context = new XmlApplicationContext(@"Config\Spring.xml");
object o = context.GetObject("HelloWorld");
object o2 = context.GetObject("HelloWorld");
Console.WriteLine(object.ReferenceEquals(o, o2)); // output: true
}
}
}
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
通过上面的配置文件我们知道,我们必须提供一个 Creator 的注入声明,同时要为 HelloWorld 指定创建者的 "factory-object" 和 "factory-method"。
4. 对象初始化方法
我们可以在配置文件中使用 "init-method" 指定类型构造方法以外的初始化方法。该方法会在对象构造方法之后被容器调用执行,以便我们完成一些初始化操作。
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Spring.Core;
using Spring.Context;
using Spring.Context.Support;
namespace ConsoleApplication1.SpringNet
{
public class HelloWorld
{
public HelloWorld()
{
}
{
public class HelloWorld
{
public HelloWorld()
{
}
public void Init()
{
Console.WriteLine("Init...");
}
}
{
Console.WriteLine("Init...");
}
}
public class Program
{
static void Main()
{
IApplicationContext context = new XmlApplicationContext(@"Config\Spring.xml");
{
static void Main()
{
IApplicationContext context = new XmlApplicationContext(@"Config\Spring.xml");
object o = context.GetObject("HelloWorld");
Console.WriteLine(o);
}
}
}
Console.WriteLine(o);
}
}
}
需要注意的是对于 Singleton 方式来说,初始化只会被执行一次,因为后续对象是直接从容器中拷贝引用而已。
5. 设置对象属性
除了在配置文件中提供构造参数外,我们还可以直接为对象属性赋值。
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Spring.Core;
using Spring.Context;
using Spring.Context.Support;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Spring.Core;
using Spring.Context;
using Spring.Context.Support;
namespace ConsoleApplication1.SpringNet
{
public class HelloWorld
{
public HelloWorld()
{
}
{
public class HelloWorld
{
public HelloWorld()
{
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
{
get { return name; }
set { name = value; }
}
public override string ToString()
{
return name;
}
}
{
return name;
}
}
public class Program
{
static void Main()
{
IApplicationContext context = new XmlApplicationContext(@"Config\Spring.xml");
object o = context.GetObject("HelloWorld");
Console.WriteLine(o);
}
}
}
http://www.springframework.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
{
static void Main()
{
IApplicationContext context = new XmlApplicationContext(@"Config\Spring.xml");
object o = context.GetObject("HelloWorld");
Console.WriteLine(o);
}
}
}
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
6. 设置类型参数
上面的例子我们注入的数据都是基本类型,对于自定义类型我们需要做些声明。下面的例子中 HelloWorld 需要 2 个构造参数,分别是一个自定义类型和 Type。
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Spring.Core;
using Spring.Context;
using Spring.Context.Support;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Spring.Core;
using Spring.Context;
using Spring.Context.Support;
namespace ConsoleApplication1.SpringNet
{
public class MyData
{
public override string ToString()
{
return "MyData...";
}
}
{
public class MyData
{
public override string ToString()
{
return "MyData...";
}
}
public class HelloWorld
{
private MyData data;
{
private MyData data;
public HelloWorld(MyData data, Type type)
{
this.data = data;
Console.WriteLine(type);
}
{
this.data = data;
Console.WriteLine(type);
}
public override string ToString()
{
return data.ToString();
}
}
{
return data.ToString();
}
}
public class Program
{
static void Main()
{
IApplicationContext context = new XmlApplicationContext(@"Config\Spring.xml");
{
static void Main()
{
IApplicationContext context = new XmlApplicationContext(@"Config\Spring.xml");
object o = context.GetObject("HelloWorld");
Console.WriteLine(o);
}
}
}
http://www.springframework.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
Console.WriteLine(o);
}
}
}
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
一定要注意,注入一个对象和一个 Type 的不同之处。
配置文件功能,将在后面做进一步介绍。
[Spring.NET IoC] 之四:配置补充
1. 别名
[Spring.NET IoC] 之四:配置补充
1. 别名
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
我们为 HelloWorld 创建了一个别名 HelloWorld2,我们同样可以通过 HelloWorld2 获取对象。请注意下面的测试代码输出结果。
object o = context.GetObject("HelloWorld");
object o2 = context.GetObject("HelloWorld2");
Console.WriteLine(object.ReferenceEquals(o, o2)); // output: true
object o2 = context.GetObject("HelloWorld2");
Console.WriteLine(object.ReferenceEquals(o, o2)); // output: true
2. 继承
下面的例子中,我们为 HelloWorld 添加了一个 "parent" 声明,该申明表示 HelloWorld 继承 test 的配置属性,包括构造参数和属性设置,但不包括 "singleton" 等。当然继承的仅仅是配置信息,而不是类型。
http://www.springframework.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
3. 内联
对于下面的配置文件,我们还可以改成内联方式。
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
修改结果
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
4. 空值
注意空值(null) 和空字符串("")不同。
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
[Spring.NET IoC] 之五:列表参数
我们可以在配置文件中向构造方法或者属性注入列表型参数,诸如 Array、ArrayList、Hashtable 等。
1. IList
在 .NET Framework 中实现 IList 的主要是 Array、ArrayList。
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
public class HelloWorld
{
public HelloWorld(IList list)
{
Console.WriteLine(list); // output: ArrayList
foreach (object o in list)
Console.WriteLine(o);
}
}
我们会发现 Spring.NET IoC 缺省使用 ArrayList 来实现 IList 列表参数。
2. IDictionary
实现 IDictionary 的最常用类型是 Hashtable。
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
public class HelloWorld
{
public HelloWorld(IDictionary dict)
{
Console.WriteLine(dict); // output:System.Collections.Specialized.HybridDictionary
foreach (object o in dict.Keys)
{
Console.WriteLine("{0}={1}", o, dict[o]);
}
}
}
看看 System.Collections.Specialized.HybridDictionary 的MSDN说明
在集合较小时,使用 ListDictionary 来实现 IDictionary,然后当集合变大时,切换到 Hashtable。
建议将该类用于字典中的元素数量未知的情况。它利用了 ListDictionary 处理小集合时性能改善的优点,同时也可灵活地切换到处理较大集合时能力比 ListDictionary 更好的 Hashtable。
如果集合的初始大小大于 ListDictionary 的最佳大小,那么集合立即存储在 Hashtable 中,以避免将元素从 ListDictionary 复制到 Hashtable 产生的系统开销。
建议将该类用于字典中的元素数量未知的情况。它利用了 ListDictionary 处理小集合时性能改善的优点,同时也可灵活地切换到处理较大集合时能力比 ListDictionary 更好的 Hashtable。
如果集合的初始大小大于 ListDictionary 的最佳大小,那么集合立即存储在 Hashtable 中,以避免将元素从 ListDictionary 复制到 Hashtable 产生的系统开销。