描述:Unity的生命周期是注册的类型对象的生命周期,而Unity默认情况下会自动帮我们维护好这些对象的生命周期,我们也可以显示配置对象的生命周期,Unity将按照配置自动管理。

//创建一个UnityContainer对象
IUnityContainer container = new UnityContainer();
IProduct milk = new Milk();
IProduct sugar = new Sugar();
//为 Milk 实例注册默认实例
container.RegisterInstance<IProduct>("Milk", milk);
//为 Sugar 实例注册命名实例,同RegisterType
container.RegisterInstance<IProduct>("Sugar", sugar);
string msg1 = container.Resolve<IProduct>("Milk").ShowInfo();
string msg2 = container.Resolve<IProduct>("Sugar").ShowInfo();
Response.Write(msg1 + "/" + msg2);

需要注意的是,使用RegisterInstance将已存在的实例注册到UnityContainer中,默认情况下其实用的是ContainerControlledLifetimeManager,这个生命周期 是由UnityContainer来进行管理,UnityContainer会维护一个对象实例的强引用,当你将已存在的实例注册到UnityContainer后,每次通过Resolve方法获取对象都是同一对象,也就是单件实例(singleton instance)。

各个Unity的生命周期管理

1.TransientLifetimeManager

瞬态生命周期,默认情况下,在使用RegisterType进行对象关系注册时如果没有指定生命周期管理器则默认使用这个生命周期管理器,这个生命周期管理器就如同其名字一样,当使用这种管理器的时候,每次通过Resolve或ResolveAll调用对象的时候都会重新创建一个新的对象。

需要注意的是,使用RegisterInstance对已存在的对象进行关系注册的时候无法指定这个生命周期,否则会报异常。

代码如下:

/// <summary>
/// 配置文件注册
/// </summary>
public void TransientLifetimeManagerCode2()
{
UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
container.LoadConfiguration(section, "MyContainer"); Response.Write("\r\n-------TransientLifetimeManager Begin------");
Response.Write("\r\n第一次调用RegisterType注册的对象HashCode:" +
container.Resolve<IProduct>("Milk").GetHashCode());
Response.Write("\r\n第二次调用RegisterType注册的对象HashCode:" +
container.Resolve<IProduct>("Milk").GetHashCode());
Response.Write("\r\n-------TransientLifetimeManager End------");
}
/// <summary>
/// 代码注册
/// </summary>
public void TransientLifetimeManagerCode1()
{
//以下2种注册效果是一样的
container.RegisterType<IProduct, Milk>();
container.RegisterType<IProduct, Milk>(new TransientLifetimeManager());
Response.Write("\r\n-------TransientLifetimeManager Begin------");
Response.Write("\r\n第一次调用RegisterType注册的对象HashCode:" +
container.Resolve<IProduct>("Milk").GetHashCode());
Response.Write("\r\n第二次调用RegisterType注册的对象HashCode:" +
container.Resolve<IProduct>("Milk").GetHashCode());
Response.Write("\r\n-------TransientLifetimeManager End------");
}

配置文件:

<!--映射关系-->
<register type="IProduct" mapTo="Milk" name="Milk">
<!--transient:瞬态生命周期,每次通过Resolve或ResolveAll调用对象的时候都会重新创建一个新的对象。-->
<lifetime type="transient" />
</register>

如果想在配置文件中在在注册关系的时候更改一个生命周期管理器只需在<register>配置节下新增<lifetime>既可(如果不新增则默认使用TransientLifetimeManager)。

其中<lifetime>有3个参数:

1)type,生命期周期管理器的类型,这边可以选择Unity内置的,也可以使用自定义的,其中内置的生命周期管理器会有智能提示。

2)typeConverter,生命周期管理器转换类,用户自定义一个生命周期管理器的时候所创建一个转换器。

3)value,初始化生命周期管理器的值。

结果:第一次调用RegisterType注册的对象HashCode:49575947 第二次调用RegisterType注册的对象HashCode:25434065

2.ContainerControlledLifetimeManager

容器控制生命周期管理,这个生命周期管理器是RegisterInstance默认使用的生命周期管理器,也就是单件实例,UnityContainer会维护一个对象实例的强引用,每次调用的时候都会返回同一对象,示例代码如下:

/// <summary>
/// ContainerControlledLifetimeManager 代码注册
/// </summary>
public void ContainerControlledLifetimeManagerCode1()
{
IProduct milk = new Milk();
container.RegisterInstance<IProduct>("Milk", milk);
Response.Write("第一次HashCode:" + container.Resolve<IProduct>("Milk").GetHashCode()); container.RegisterInstance<IProduct>("Milk", milk, new ContainerControlledLifetimeManager());
Response.Write("第二次HashCode:" + container.Resolve<IProduct>("Milk").GetHashCode());
}

配置文件:<lifetime type="singleton" />

结果:第一次HashCode:38580545 第二次HashCode:38580545

3.HierarchicalLifetimeManager
分层生命周期管理器,这个管理器类似于ContainerControlledLifetimeManager,也是由UnityContainer来管理,也就是单件实例。

不过与ContainerControlledLifetimeManager不同的是,这个生命周期管理器是分层的,因为Unity的容器时可以嵌套的,所以这个生命周期管理器就是针对这种情况,当使用了这种生命周期管理器,父容器和子容器所维护的对象的生命周期是由各自的容器来管理,代码如下:

/// <summary>
/// 分层生命周期管理器 代码注册
/// </summary>
public void HierarchicalLifetimeManagerCode1()
{
container.RegisterType<IProduct, Milk>(new HierarchicalLifetimeManager());
//创建子容器
var childContainer = container.CreateChildContainer();
childContainer.RegisterType<IProduct, Milk>(new HierarchicalLifetimeManager()); Response.Write("第一次HashCode:" + container.Resolve<IProduct>().GetHashCode());
Response.Write("第二次HashCode:" + container.Resolve<IProduct>().GetHashCode());
Response.Write("子容器 第一次HashCode:" + childContainer.Resolve<IProduct>().GetHashCode());
Response.Write("子容器 第二次HashCode:" + childContainer.Resolve<IProduct>().GetHashCode());
}

配置文件:<lifetime type="hierarchical" />

结果:第一次HashCode:44778609第二次HashCode:44778609子容器 第一次HashCode:6476987子容器 第二次HashCode:6476987

注:这边需要提一下的就是,Unity这种分级容器的好处就在于我们可以对于有不同生命周期的对象放在不同的容器中,如果一个子容器被释放,不会影响到其它子容器中的对象,但是如果根节点处父容器释放后,所有的子容器都将被释放。

4.PerResolveLifetimeManager
这个生命周期是为了解决循环引用而重复引用的生命周期,先看一下微软官方给出的实例:

public interface IPresenter
{ } public class MockPresenter : IPresenter
{
public IView View { get; set; } public MockPresenter(IView view)
{
View = view;
}
} public interface IView
{
IPresenter Presenter { get; set; }
} public class View : IView
{
[Dependency]
public IPresenter Presenter { get; set; }
}

从这个例子中可以看出,有2个接口IPresenter和IView,还有2个类MockPresenter和View分别实现这2个接口,同时这2个类 中都包含了对另外一个类的对象属性,这个就是一个循环引用,而对应的这个生命周期管理就是针对这种情况而新增的,其类似于 TransientLifetimeManager,但是其不同在于,如果应用了这种生命周期管理器,则在第一调用的时候会创建一个新的对象,而再次通过 循环引用访问到的时候就会返回先前创建的对象实例(单件实例),代码如下:

public void PerResolveLifetimeManagerCode()
{
var container = new UnityContainer()
.RegisterType<IPresenter, MockPresenter>()
.RegisterType<IView, View>(new PerResolveLifetimeManager()); var view = container.Resolve<IView>();
var tempPresenter = container.Resolve<IPresenter>();
var realPresenter = (MockPresenter)view.Presenter; txtResult.Text += "-------PerResolveLifetimeManager Begin------ <br />"; txtResult.Text += ("使用了PerResolveLifetimeManager的对象 Begin <br />");
txtResult.Text += ("通过Resolve方法获取的View对象:" + view.GetHashCode() + " <br />");
txtResult.Text += ("View对象中的Presenter对象所包含的View对象:" + realPresenter.View.GetHashCode() + " <br />");
txtResult.Text += ("使用了PerResolveLifetimeManager的对象 End <br />"); txtResult.Text += ("未使用PerResolveLifetimeManager的对象 Begin <br />");
txtResult.Text += ("View对象中的Presenter对象:" + realPresenter.GetHashCode() + " <br />");
txtResult.Text += ("通过Resolve方法获取的View对象:" + tempPresenter.GetHashCode() + " <br />");
txtResult.Text += ("未使用PerResolveLifetimeManager的对象 End <br />");
txtResult.Text += ("-------PerResolveLifetimeManager Begin------");
}

从代码中可以看出,在注册对象的时候,仅对IView和View应用了PerResolveLifetimeManager,所以第二次访问View对象会返回同一实例。
具体配置文件如下,有关构造函数注入和属性注入的内容在下一篇文章中进行介绍:

<alias alias="IPresenter" type="UnityStudyConsole.IPresenter, UnityStudyConsole" />
<alias alias="IView" type="UnityStudyConsole.IView, UnityStudyConsole" />
<alias alias="MockPresenter" type="UnityStudyConsole.MockPresenter, UnityStudyConsole" />
<alias alias="View" type="UnityStudyConsole.View, UnityStudyConsole" />
<container name="Second">
<register type="IPresenter" mapTo="MockPresenter">
<constructor>
<param name ="view" type="IView">
</param>
</constructor>
</register>
<register type="IView" mapTo="View" >
<lifetime type="perresolve"/>
<property name="Presenter" dependencyType="IPresenter"></property>
</register>
</container>

  结果:

-------PerResolveLifetimeManager Begin------ 
使用了PerResolveLifetimeManager的对象 Begin 
通过Resolve方法获取的View对象:60062986 
View对象中的Presenter对象所包含的View对象:60062986 
使用了PerResolveLifetimeManager的对象 End 
未使用PerResolveLifetimeManager的对象 Begin 
View对象中的Presenter对象:58180283 
通过Resolve方法获取的View对象:14497132 
未使用PerResolveLifetimeManager的对象 End 
-------PerResolveLifetimeManager Begin------

可以看出2次调用View对象的HashCode都是一样的,而Presenter对象的HashCode不同。

5.PerThreadLifetimeManager

每线程生命周期管理器,就是保证每个线程返回同一实例,具体代码如下:

public void PerThreadLifetimeManagerCode()
{
container.RegisterType<IProduct, Milk>("Milk", new PerThreadLifetimeManager());
var thread = new Thread(new ParameterizedThreadStart(Thread1));
txtResult.Text += ("-------PerResolveLifetimeManager Begin------ <br />");
txtResult.Text += ("默认线程 Begin <br />");
txtResult.Text += ("第一调用:" + container.Resolve<IProduct>("Milk").GetHashCode() + " <br />");
txtResult.Text += ("第二调用:" + container.Resolve<IProduct>("Milk").GetHashCode() + " <br />");
txtResult.Text += ("默认线程 End <br /> <br />");
thread.Start(container);
}
public void Thread1(object obj)
{
var tmpContainer = obj as UnityContainer;
txtResult.Text += ("新建线程 Begin <br />");
txtResult.Text += ("第一调用:" + tmpContainer.Resolve<IProduct>("Milk").GetHashCode() + " <br />");
txtResult.Text += ("第二调用:" + tmpContainer.Resolve<IProduct>("Milk").GetHashCode() + " <br />");
txtResult.Text += ("新建线程 End <br />");
txtResult.Text += ("-------PerResolveLifetimeManager End------");
}

结果:

-------PerResolveLifetimeManager Begin------ 
默认线程 Begin 
第一调用:33863240 
第二调用:33863240 
默认线程 End

新建线程 Begin 
第一调用:20518217 
第二调用:20518217 
新建线程 End 
-------PerResolveLifetimeManager End------

注:一般来说不建议在使用RegisterInstance对已存在的对象注册关系时使用PerThreadLifetimeManager,因为此时的对象已经在一个线程内创建了,如果再使用这个生命周期管理器,将无法保证其正确调用。

6.ExternallyControlledLifetimeManager

外部控制生命周期管理器,这个生命周期管理允许你使用RegisterType和RegisterInstance来注册对象之间的关系,但是其只会对对象保留一个弱引用,其生命周期交由外部控制,也就是意味着你可以将这个对象缓存或者销毁而不用在意UnityContainer,而当其他地方没有强引用这个对象时,其会被GC给销毁 掉。

在默认情况下,使用这个生命周期管理器,每次调用Resolve都会返回同一对象(单件实例),如果被GC回收后再次调用Resolve方法将会重新创建新的对象,示例代码如下:

public void ExternallyControlledLifetimeManagerCode()
{
container.RegisterType<IProduct, Milk>(new ExternallyControlledLifetimeManager());
var myClass1 = container.Resolve<IProduct>();
var myClass2 = container.Resolve<IProduct>();
txtResult.Text += ("-------ExternallyControlledLifetimeManager Begin------ <br />");
txtResult.Text += ("第一次调用:" + myClass1.GetHashCode() + " <br />");
txtResult.Text += ("第二次调用:" + myClass2.GetHashCode() + " <br />"); myClass1 = myClass2 = null;
GC.Collect(); txtResult.Text += ("****GC回收过后**** <br />");
txtResult.Text += ("第一次调用:" + container.Resolve<IProduct>().GetHashCode() + " <br />");
txtResult.Text += ("第二次调用:" + container.Resolve<IProduct>().GetHashCode() + " <br />");
txtResult.Text += ("-------ExternallyControlledLifetimeManager End------");
}

结果:

-------ExternallyControlledLifetimeManager Begin------ 
第一次调用:51935804 
第二次调用:51935804 
****GC回收过后**** 
第一次调用:22470659 
第二次调用:22470659 
-------ExternallyControlledLifetimeManager End------

来源:http://www.cnblogs.com/qqlin/archive/2012/10/17/2720829.html

原文链接:http://www.cnblogs.com/kyo-yo/archive/2010/11/10/Learning-EntLib-Tenth-Decoupling-Your-System-Using-The-Unity-PART2-Learn-To-Use-Unity-Two.html

Unity(二)生命周期LifetimeManager的更多相关文章

  1. Unity脚本生命周期

    前言 说到生命周期,影响最深刻的是,在接触Java的JSF组件时,JSF组件的五大生命周期,全要默写出来,嘿嘿…… 总结这两天在写小怪和掉落的糖葫芦时,老是遇到GameObject未销毁,一直存在场景 ...

  2. Spring之bean二生命周期

    上一博客主要学习了下bean的配置.注入.自定义属性编辑器,今天来熟悉bean的生命周期.在开发中生命周期是一个很常见的名词,基本每种编程语言都能找到与它关联的.关于bean的生命周期我在网上也找了好 ...

  3. Unity脚本生命周期与执行顺序

    文章目录 脚本生命周期 MonoBehavior生命周期图 脚本执行顺序 自定义执行顺序 在Unity中,脚本可以理解为附加在游戏对象上的用于定义游戏对象行为的指令代码.必须绑定在游戏对象上才能开始它 ...

  4. react基础学习 二——生命周期

    生命周期mount: mounting装载创建 update更新 unmounting卸载 错误捕获 注意点:生命周期函数的 作用,什么之后用 只有类式组件有生命周期,函数式组件没有生命周期 moun ...

  5. react学习二 生命周期

    转自:https://www.cnblogs.com/gdsblog/p/7348375.html react 中compent getDefaultProps object getDefaultPr ...

  6. VUE 学习笔记 二 生命周期

    1.除了数据属性,Vue 实例还暴露了一些有用的实例属性与方法.它们都有前缀 $,以便与用户定义的属性区分开来 var data = { a: 1 } var vm = new Vue({ el: ' ...

  7. Mybatis精讲(二)---生命周期

    目录 回顾 SqlSessionFactoryBuilder SqlSessionFactory openSessionFromDataSource Executor SqlSession Mappe ...

  8. Spring注解驱动开发(二)-----生命周期、属性赋值

    bean的生命周期 bean的生命周期:bean创建---初始化----销毁的过程容器管理bean的生命周期:我们可以自定义初始化和销毁方法:容器在bean进行到当前生命周期的时候来调用我们自定义的初 ...

  9. VUE二 生命周期详解

    vue官网对vue生命周期的介绍 Vue实例有一个完整的生命周期,也就是从开始创建.初始化数据.编译模板.挂载Dom.渲染→更新→渲染.销毁等一系列过程,我们称这是Vue的生命周期.通俗说就是Vue实 ...

随机推荐

  1. WPF中嵌入普通Win32程序的方法

    公司现在在研发基于.Net中WPF技术的产品,由于要兼容旧有产品,比如一些旧有的Win32程序.第三方的Win32程序等等,还要实现自动登录这些外部Win32程序,因此必须能够将这些程序整合到我们的系 ...

  2. How to Failover the ‘Cluster Group’

    If you have more than two nodes in the cluster, you can specify the destination node with the follow ...

  3. JavaScript常用小技巧

    1.获取访问地址URL的参数 <script type="text/javascript"> var param = ""; var nowUrl ...

  4. js 生成 yyyy-mm-dd 格式的逼格姿势

    关于 js 生成 yyyy-mm-dd 格式,往往都会采取手动拼接,一般不愿意为了小功能而去动用 momentjs 之类的插件. ps: 只分享简单方法,网上有 N 多 dateformat 代码,这 ...

  5. Python-Tkinter几何布局管理(转)

    所有的Tkinter组件都包含专用的几何管理方法,这些方法是用来组织和管理整个父配件区中子配件的布局的.Tkinter提供了截然不同的三种几何管理类:pack.grid和place. pack() p ...

  6. delphi 常用的将窗口置前的函数

    function BringWindowToTopEx(hWnd: HWND): Boolean;begin if IsIconic(hWnd) then ShowWindow(hWnd, SW_RE ...

  7. [CF #290-C] Fox And Names (拓扑排序)

    题目链接:http://codeforces.com/contest/510/problem/C 题目大意:构造一个字母表,使得按照你的字母表能够满足输入的是按照字典序排下来. 递归建图:竖着切下来, ...

  8. 【转】操作权限不够?教你开启Win7管理员帐户

    在Win7中进行一些设置,或修改某些文件时,经常会弹出当前帐户没有操作权限的提示,即使已经是管理员账户也不行.事实上,出于安全方面的考虑,默认情况下Win7系统的系统管理员Administrator账 ...

  9. apache+tomcat分布式集群搭建

    今天搭建apche+tomcat分布式集群,遇到很多问题,在网上找到的很多都不成功,然后和同事一起研究了一下,最终搭建成功了.做个笔记,以备自己以后参考. 1,下载apache.在下载Apache(2 ...

  10. nginx的Location的总结以及rewrite规则的总结

    Location的语法: location 有”定位”的意思, 根据Uri来进行不同的定位. 在虚拟主机的配置中,是必不可少的,location可以把网站的不同部分,定位到不同的处理方式上. 比如,  ...