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及扩展类(对象后处理器)就留在下篇写吧!

第四章 Spring.Net 如何管理您的类___自定义对象行为的更多相关文章

  1. 第四章 Spring.Net 如何管理您的类___让对象了解自己的容器

    我们在开发中,经常需要让对象了解自己所在的容器的信息,例如,有时我们需要让对象知道,对象所在容器的引用是什么,或者是对象在容器中的名称是什么 .Spring.Net 中提供了两个接口,我们使用这两个接 ...

  2. 第四章 Spring.Net 如何管理您的类___对象、对象工厂和应用程序上下文

    在前面一章我们介绍了依赖注入,控制反转的概念,以及自己动手搭建了一下Spring.Net的环境.通过这些操作,我们知道了Spring.Net 的核心是使用依赖注入或控制反转这种思想来管理业务对象,降低 ...

  3. 第四章 Spring.Net 如何管理您的类___对象的手动装配

    前面我们知道了什么是对象,什么是对象工厂,什么是应用程序上下文.这一次我们来看一下对象的装配. Spring.Net 中有多种装配对象的方式,装配这个词可能比较学术化,我们可以理解为对象的创建. Sp ...

  4. 第四章 Spring.Net 如何管理您的类___对象的自动装配

    由于这几天都比较忙,所以对笔记暂时没有更新. Spring.NET具有自动装配的能力,也就是说,Spring.NET可以通过对象的定义自动分辨某个对象的协作对象.自动装配是针对单个对象(按:针对每个协 ...

  5. 第四章 Spring.Net 如何管理您的类___统一资源访问接口

    在前面章节有童鞋提到过 关于配置文件 Objects.xml 路径的相关问题,这些东西是 IResource 接口的一些内容,接下来就详细介绍一下 IResource 接口. IResource 接口 ...

  6. 第四章 Spring.Net 如何管理您的类___对象的生命周期链

    各位,实在不好意思,因为有事,博客几天没更新了.前面有童鞋提到,配置 Objects.xml 路径的相关问题,这些东西是 IResource 接口的一些内容.在下一章会详细介绍. 传统的Net应用中, ...

  7. 第四章 Spring.Net 如何管理您的类___对象的作用域

    Spring.Net 中对象的作用域,就是描述对象的部署模式 ,Spring.Net 中对象可以通过两种模式布署: ① singleton(单例模式) ② 非singleton 也叫非单例模式(或者叫 ...

  8. 第四章 Spring.Net 如何管理您的类___对象的初始化方式

    在 Spring.Net 中对象初始化的方式分为两种: ① 急切实例化,也就是说 Spring.Net 容器初始化的时候将对象先实例化出来. ② 延迟实例化,也就是说我们在调用 GetObject 方 ...

  9. 第四章 Spring.Net 如何管理您的类___IObjectPostProcessor接口

    官方取名叫 对象后处理器 (object post-processor) , 听起来很高级的样子啊!实际上就是所有实现了这个接口的类,增加了两个方法. Spring.Objects.Factory.C ...

随机推荐

  1. Spring Boot干货系列:(三)启动原理解析

    Spring Boot干货系列:(三)启动原理解析 2017-03-13 嘟嘟MD 嘟爷java超神学堂 前言 前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说 ...

  2. 采用Filter的方法解决HttpServletRequest.getParameter乱码的问题

    其实就是利用这么一个原理: byte[] bytes = str.getBytes("iso-8859-1"); String result = new String(bytes, ...

  3. sqlalchemy多表联合查询(inner outer join 左右连接)详解

    #按用户名摸糊查询trans_details.query.join(Uses).filter(Users.username.like('%xx%'))#select xxx from trans_de ...

  4. FreeRTOS基础篇教程目录汇总

    以下教程(大部分章节)(尤其理论介绍部分)转载自安富莱电子,官网链接: http://forum.armfly.com/forum.php 然后根据安富莱的教程自己做了分析和测试,希望大家共同进步. ...

  5. hbase中double类型数据做累加

    public static Result incr(String tableFullName, String rowKey, String family, String qualifier, long ...

  6. 【WPF/C#】测试下载文件(图片)

    需求:界面上有一个按钮,点击后联网下载一张PNG图片,保存到本地指定路径. 重要参考: http://stackoverflow.com/questions/24797485/how-to-downl ...

  7. C语言 · 输出日历

    算法提高 输出日历   时间限制:1.0s   内存限制:512.0MB      按照下述格式打印2006年12月日历: Calendar 2006-12---------------------- ...

  8. C语言 · 成绩的等级输出

    输入一个百分制的成绩t后,按下式输出它的等级.等级为:90~100为A,80~89为B,70~79为C,60~69为D,0~59为E. 样例输入 98 样例输出 A   #include<std ...

  9. Android——对话框2(日期和时间对话框)

    xml <Button android:layout_width="match_parent" android:layout_height="wrap_conten ...

  10. Android——RadioGroup和CheckBox

    xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android= ...