[IoC容器Unity]第二回:Lifetime Managers生命周期
1.引言
Unity的生命周期是注册的类型对象的生命周期,而Unity默认情况下会自动帮我们维护好这些对象的生命周期,我们也可以显示配置对象的生命周期,Unity将按照配置自动管理,非常方便,下面就介绍一下 Unity中内置的生命周期管理器。
2.Lifetime Managers生命周期管理
准备以下类关系,用于演示
有2个接口类:IClass(班级接口)和ISubject(科目接口),其分别有2个实现类。看下面一个示例
public static void RegisterInstance()
{
IClass myClass = new MyClass();
IClass yourClass = new YourClass();
//为myClass实例注册默认实例
container.RegisterInstance<IClass>(myClass);
//为yourClass实例注册命名实例,同RegisterType
container.RegisterInstance<IClass>("yourInstance", yourClass); container.Resolve<IClass>().ShowInfo();
container.Resolve<IClass>("yourInstance").ShowInfo();
}
这段代码很简单,就是通过RegisterInstance方法为已存在的对象进行注册,这样可以通过UnityContainer来管理这些对象实例的生命周期。
需要注意的是,使用RegisterInstance来将已存在的 实例注册到UnityContainer中,默认情况下其实用的是ContainerControlledLifetimeManager,这个生命周期 是由UnityContainer来进行管理,UnityContainer会维护一个对象实例的强引用,当你将已存在的实例注册到 UnityContainer后,每次通过Resolve方法获取对象都是同一对象,也就是单件实例(singleton instance),具体有关生命周期相关信息在下面进行介绍。
由于RegisterInstance是对已存在的实例进行注册,所以无法通过配置文件来进行配置。有关RegisterInstance方法的其他重载我这边就不详细介绍了,可以点此查看详细的重载方法介绍。
下面将详细介绍各个Unity的生命周期管理
2.1 TransientLifetimeManager
瞬态生命周期,默认情况下,在使用RegisterType进行对象关系注册时如果没有指定生命周期管理器则默认使用这个生命周期管理器,这个生命周期管理器就如同其名字一样,当使用这种管理器的时候,每次通过Resolve或ResolveAll调用对象的时候都会重新创建一个新的对象。
需要注意的是,使用RegisterInstance对已存在的对象进行关系注册的时候无法指定这个生命周期,否则会报异常。
代码如下:
public static void TransientLifetimeManagerCode()
{
//以下2种注册效果是一样的
container.RegisterType<IClass, MyClass>();
container.RegisterType<IClass, MyClass>(new TransientLifetimeManager());
Console.WriteLine("-------TransientLifetimeManager Begin------");
Console.WriteLine("第一次调用RegisterType注册的对象HashCode:" +
container.Resolve<IClass>().GetHashCode());
Console.WriteLine("第二次调用RegisterType注册的对象HashCode:" +
container.Resolve<IClass>().GetHashCode());
Console.WriteLine("-------TransientLifetimeManager End------");
}
配置文件如下:
<register type="IClass" mapTo="MyClass">
<lifetime type="transient" />
<!--<lifetime type="SessionLifetimeManager"
value="Session#1" typeConverter="SessionLifetimeConverter" />-->
</register>
如果想在配置文件中在在注册关系的时候更改一个生命周期管理器只需在<register>配置节下新增<lifetime>既可(如果不新增则默认使用TransientLifetimeManager)。
其中<lifetime>有3个参数:
1)type,生命期周期管理器的类型,这边可以选择Unity内置的,也可以使用自定义的,其中内置的生命周期管理器会有智能提示。
2)typeConverter,生命周期管理器转换类,用户自定义一个生命周期管理器的时候所创建一个转换器。
3)value,初始化生命周期管理器的值。
配置文件读取代码:
public static void TransientLifetimeManagerConfiguration()
{
//获取指定名称的配置节
UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
container.LoadConfiguration(section, "First"); Console.WriteLine("-------TransientLifetimeManager Begin------");
Console.WriteLine("第一次调用RegisterType注册的对象HashCode:" +
container.Resolve<IClass>("transient").GetHashCode());
Console.WriteLine("第二次调用RegisterType注册的对象HashCode:" +
container.Resolve<IClass>("transient").GetHashCode());
Console.WriteLine("-------TransientLifetimeManager End------");
}
效果图如下,可以看出每次产生的对象都是不同的:
2.2 ContainerControlledLifetimeManager
容器控制生命周期管理,这个生命周期管理器是RegisterInstance默认使用的生命周期管理器,也就是单件实例,UnityContainer会维护一个对象实例的强引用,每次调用的时候都会返回同一对象,示例代码如下:
public static void ContainerControlledLifetimeManagerCode()
{
IClass myClass = new MyClass();
//以下2种注册效果是一样的
container.RegisterInstance<IClass>("ccl", myClass);
container.RegisterInstance<IClass>("ccl", myClass, new ContainerControlledLifetimeManager()); container.RegisterType<IClass, MyClass>(new ContainerControlledLifetimeManager());
Console.WriteLine("-------ContainerControlledLifetimeManager Begin------");
Console.WriteLine("第一次调用RegisterType注册的对象HashCode:" +
container.Resolve<IClass>().GetHashCode());
Console.WriteLine("第二次调用RegisterType注册的对象HashCode:" +
container.Resolve<IClass>().GetHashCode());
Console.WriteLine("第一次调用RegisterInstance注册的对象HashCode:" +
container.Resolve<IClass>("ccl").GetHashCode());
Console.WriteLine("第二次调用RegisterInstance注册的对象HashCode:" +
container.Resolve<IClass>("ccl").GetHashCode());
Console.WriteLine("-------ContainerControlledLifetimeManager End------");
}
配置文件如下:
<register type="IClass" mapTo="MyClass" name="ccl">
<lifetime type="singleton" />
</register>
效果图如下,可以看出每次获取的对象都是同一对象:
2.3 HierarchicalLifetimeManager
分层生命周期管理器,这个管理器类似于ContainerControlledLifetimeManager,也是由UnityContainer来管理,也就是单件实例。不过与ContainerControlledLifetimeManager不 同的是,这个生命周期管理器是分层的,因为Unity的容器时可以嵌套的,所以这个生命周期管理器就是针对这种情况,当使用了这种生命周期管理器,父容器 和子容器所维护的对象的生命周期是由各自的容器来管理,代码如下(RegisterInstance情况也类似,这边就不展示了)
public static void HierarchicalLifetimeManagerCode()
{
container.RegisterType<IClass, MyClass>(new HierarchicalLifetimeManager());
//创建子容器
var childContainer = container.CreateChildContainer();
childContainer.RegisterType<IClass, MyClass>(new HierarchicalLifetimeManager()); Console.WriteLine("-------ContainerControlledLifetimeManager Begin------");
Console.WriteLine("第一次调用父容器注册的对象HashCode:" +
container.Resolve<IClass>().GetHashCode());
Console.WriteLine("第二次调用父容器注册的对象HashCode:" +
container.Resolve<IClass>().GetHashCode());
Console.WriteLine("第一次调用子容器注册的对象HashCode:" +
childContainer.Resolve<IClass>().GetHashCode());
Console.WriteLine("第二次调用子容器注册的对象HashCode:" +
childContainer.Resolve<IClass>().GetHashCode());
Console.WriteLine("-------ContainerControlledLifetimeManager End------");
}
由于配置文件不能配置这种层级效果,所以配置这种生命周期时只需要更改下生命周期名称:
<register type="IClass" mapTo="MyClass" name="hl">
<lifetime type="hierarchical" />
</register>
具体的效果图如下,可以看出父级和子级维护不同对象实例:
这边需要提一下的就是,Unity这种分级容器的好处就在于我们可以对于有不同生命周期的对象放在不同的容器中,如果一个子容器被释放,不会影响到其它子容器中的对象,但是如果根节点处父容器释放后,所有的子容器都将被释放。
2.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 static 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; Console.WriteLine("-------PerResolveLifetimeManager Begin------");
Console.WriteLine("使用了PerResolveLifetimeManager的对象 Begin");
Console.WriteLine("通过Resolve方法获取的View对象:" +
view.GetHashCode());
Console.WriteLine("View对象中的Presenter对象所包含的View对象:" +
realPresenter.View.GetHashCode());
Console.WriteLine("使用了PerResolveLifetimeManager的对象 End");
Console.WriteLine("");
Console.WriteLine("未使用PerResolveLifetimeManager的对象 Begin");
Console.WriteLine("View对象中的Presenter对象:" +
realPresenter.GetHashCode());
Console.WriteLine("通过Resolve方法获取的View对象:" +
tempPresenter.GetHashCode());
Console.WriteLine("未使用PerResolveLifetimeManager的对象 End");
Console.WriteLine("-------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>
读取配置文件代码类似于前面其他配置文件读取代码,这里就不展示,具体请看示例代码。
具体的效果图如下:
可以看出2次调用View对象的HashCode都是一样的,而Presenter对象的HashCode不同。
2.5 PerThreadLifetimeManager
每线程生命周期管理器,就是保证每个线程返回同一实例,具体代码如下:
public static void PerThreadLifetimeManagerCode()
{
container.RegisterType<IClass, MyClass>(new PerThreadLifetimeManager());
var thread = new Thread(new ParameterizedThreadStart(Thread1));
Console.WriteLine("-------PerResolveLifetimeManager Begin------");
Console.WriteLine("默认线程 Begin");
Console.WriteLine("第一调用:" +
container.Resolve<IClass>().GetHashCode());
Console.WriteLine("第二调用:" +
container.Resolve<IClass>().GetHashCode());
Console.WriteLine("默认线程 End");
thread.Start(container);
}
public static void Thread1(object obj)
{
var tmpContainer = obj as UnityContainer;
Console.WriteLine("新建线程 Begin");
Console.WriteLine("第一调用:" +
tmpContainer.Resolve<IClass>().GetHashCode());
Console.WriteLine("第二调用:" +
tmpContainer.Resolve<IClass>().GetHashCode());
Console.WriteLine("新建线程 End"); Console.WriteLine("-------PerResolveLifetimeManager End------");
}
有关配置相关的代码与前面的生命周期管理器差不多,这边就不贴代码了,请看示例代码。
具体效果图如下:
同时需要注意的是,一般来说不建议在使用RegisterInstance对已存在的对象注册关系时使用PerThreadLifetimeManager,因为此时的对象已经在一个线程内创建了,如果再使用这个生命周期管理器,将无法保证其正确调用。
2.6 ExternallyControlledLifetimeManager
外部控制生命周期管理器,这个 生命周期管理允许你使用RegisterType和RegisterInstance来注册对象之间的关系,但是其只会对对象保留一个弱引用,其生命周期 交由外部控制,也就是意味着你可以将这个对象缓存或者销毁而不用在意UnityContainer,而当其他地方没有强引用这个对象时,其会被GC给销毁 掉。
在默认情况下,使用这个生命周期管理器,每次调用Resolve都会返回同一对象(单件实例),如果被GC回收后再次调用Resolve方法将会重新创建新的对象,示例代码如下:
public static void ExternallyControlledLifetimeManagerCode()
{
container.RegisterType<IClass, MyClass>(new ExternallyControlledLifetimeManager());
var myClass1 = container.Resolve<IClass>();
var myClass2 = container.Resolve<IClass>();
Console.WriteLine("-------ExternallyControlledLifetimeManager Begin------");
Console.WriteLine("第一次调用:" +
myClass1.GetHashCode());
Console.WriteLine("第二次调用:" +
myClass2.GetHashCode());
myClass1 = myClass2 = null;
GC.Collect();
Console.WriteLine("****GC回收过后****");
Console.WriteLine("第一次调用:" +
container.Resolve<IClass>().GetHashCode());
Console.WriteLine("第二次调用:" +
container.Resolve<IClass>().GetHashCode()); Console.WriteLine("-------ExternallyControlledLifetimeManager End------");
}
有关配置相关的代码与前面的生命周期管理器差不多,这边就不贴代码了,请看示例代码。
效果图如下:
3.小结
由于自己在学习Unity,在查找相关资料,在园子里找到这篇,看了一下还是很不错的,于是转载了,原文链接: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,里面的文章写的蛮好的,大家可以查考。
[IoC容器Unity]第二回:Lifetime Managers生命周期的更多相关文章
- [转载][IoC容器Unity]第二回:Lifetime Managers生命周期
1.引言 Unity的生命周期是注册的类型对象的生命周期,而Unity默认情况下会自动帮我们维护好这些对象的生命周期,我们也可以显示配置对象的生命周期,Unity将按照配置自动管理,非常方便,下面就介 ...
- [IoC容器Unity]第四回:使用范例
1.引言 前面几个章节介绍了Unity的基本使用,主要分为程序和配置文件两种方法的使用,可以参考一下链接, [IoC容器Unity]第一回:Unity预览 [IoC容器Unity]第二回:Lifeti ...
- [IoC容器Unity]第三回:依赖注入
1.引言 上节介绍了,Unity的Lifetime Managers生命周期,Unity具体实现依赖注入包含构造函数注入.属性注入.方法注入,所谓注入相当赋值,下面一个一个来介绍. 2.构造函数注入 ...
- IOC容器Unity的使用及独立配置文件Unity.Config
[本段摘录自:IOC容器Unity 使用http://blog.csdn.net/gdjlc/article/details/8695266] 面向接口实现有很多好处,可以提供不同灵活的子类实现,增加 ...
- [IoC容器Unity] :Unity预览
1.引言 高内聚,低耦合成为一个OO架构设计的一个参考标准.高内聚是一个模块或者一个类中成员跟这个模块或者类的关系尽量高,低耦合是不同模块或者不同类之间关系尽量简单. 拿咱国家举例来说,假如你是中国人 ...
- [IoC容器Unity]第一回:Unity预览
1.引言 高内聚,低耦合成为一个OO架构设计的一个参考标准.高内聚是一个模块或者一个类中成员跟这个模块或者类的关系尽量高,低耦合是不同模块或者不同类之间关系尽量简单. 拿咱国家举例来说,假如你是中国人 ...
- Autofac容器对象实例的几种生命周期类型
实例范围决定了如何在同一服务的请求之间共享实例. 请注意,您应该熟悉生命周期范围的概念,以便更好地理解此处发生的情况. 当请求服务时,Autofac可以返回单个实例(单实例作用域),新实例(每个依赖作 ...
- 018-019 NET5_内置容器支持依赖注入+IServiceCollection的生命周期
概念: DI依赖注入: IServiceCollection仅支持构造函数注入 什么是依赖注入? 如果对象A依赖对象B,对象B依赖对象C,就可以先构造对象C,然后传递给对象B,再把对象B传递给A.得到 ...
- ASP.NET Core :容器注入(二):生命周期作用域与对象释放
//瞬时生命周期 ServiceCollection services = new ServiceCollection(); services.AddTransient<TestServiceI ...
随机推荐
- 搭建docker私有仓库
保存镜像的地方成为仓库(registry).目前有2种仓库:公共仓库和私有仓库. 最方便的是使用公共仓库上传和下载镜像,下载不需要注册,上传需要到公共仓库注册.公共仓库网站:https://hub.d ...
- UISplitViewController使用
分割控制器UISplitViewController <1>功能:它也是ipad的一个新特性,在屏幕上可以同时显示两个控制器,左边一个,右边一个:左边的为主控制器,右边的为详细控制器,主控 ...
- TCP/IP协议 网络层
IP协议介绍 1.IP协议是TCP/IP协议族中最为核心的协议.IP协议将多个包交换网络连接起来,它在源地址和目的地址之间传送一种称为数据包的东西,它还提供对数据大小的重新组装功能,以适应不同网络对包 ...
- 2018DDCTF misc1
一.题目: (╯°□°)╯︵ ┻━┻ d4e8e1f4a0f7e1f3a0e6e1f3f4a1a0d4e8e5a0e6ece1e7a0e9f3baa0c4c4c3d4c6fbb9e1e6b3e3b9e ...
- 使用PL/SQL能查询oracle中数据,在for update 语句中一直卡住
原因:在oracle中,执行了update或者insert语句后,都会要求commit,如果不commit却强制关闭连接,oracle就会将这条提交的记录锁住.下次就不能执行增删操作. 解决:1.查询 ...
- java消息队列--ActiveMQ
1.下载安装ActiveMQ ActiveMQ官网下载地址:http://activemq.apache.org/download.html ActiveMQ 提供了Windows 和Linux.Un ...
- 5分钟安装 关于win10安装composer PHP 用来管理依赖(dependency)关系的工具
1.在你的phpstudy或者wamp中开启extension=php_openssl.dll扩展 (php配置文件)并配置好php的环境变量 2.在与你安装phpstudy和wamp不一样的盘中创建 ...
- warnings.warn("allowed_domains accepts only domains, not URLs. Ignoring URL entry %s in allowed_doma
多页面循环爬取数据抛出如下异常 warnings.warn("allowed_domains accepts only domains, not URLs. Ignoring URL ent ...
- 安装mysql时出现应用程序无法正常启动(0xc000007b)
在重装mysql数据库(解压版)遇到了无法正常启动(0xc000007b)问题解决方案 问题描述: 在cmd控制台,mysql的安装路径下使用mysql install命令出现以下无法正常启动(0xc ...
- linux 邮件服务器—Extmail
环境: Centos 6.5 :172.16.9.13 (DNS 服务器) Centos 6.5: 172.16.9.11 (postfix 邮件服务器) 安装软件: yum -y install p ...