基于Unity容器中的对象生存期管理分析

IoC容器的对象生存期管理

如果你一直在使用IoC容器,你可能已经使用过了一些对象生存期管理模型(Object Lifetime Management)。通过对对象生存期的管理,将使对象的复用成为可能。同时其使容器可以控制如何创建和管理对象实例。

Unity提供的对象生存期管理模型是通过从抽象类LifetimeManager的派生类来完成。Unity将为每个类型的注册创建生存期管理器。每当UnityContainer需要创建一个新的对象实例时,将首先检测该对象类型的生存期管理器,是否已有一个对象实例可用。如果没有对象实例可用,则UnityContainer将基于配置的信息构造该对象实例并将该对象交予对象生存期管理器。

LifetimeManager

LifetimeManager是一个抽象类,其实现了ILifetimePolicy接口。该类被作为所有内置或自定义的生存期管理器的父类。它定义了3个方法: GetValue - 返回一个已经存储在生存期管理器中对象实例。 SetValue - 存储一个新对象实例到生存期管理器中。 RemoveValue - 从生存期管理器中将已存储的对象实例删除。UnityContainer的默认实现将不会调用此方法,但可在定制的容器扩展中调用。

Unity内置了6种生存期管理模型,其中有2种即负责对象实例的创建也负责对象实例的销毁(Disposing)。

•TransientLifetimeManager - 为每次请求生成新的类型对象实例。 (默认行为)
•ContainerControlledLifetimeManager - 实现Singleton对象实例。 当容器被Disposed后,对象实例也被Disposed。
•HierarchicalifetimeManager - 实现Singleton对象实例。但子容器并不共享父容器实例,而是创建针对字容器的Singleton对象实例。当容器被Disposed后,对象实例也被Disposed。
•ExternallyControlledLifetimeManager - 实现Singleton对象实例,但容器仅持有该对象的弱引用(WeakReference),所以该对象的生存期由外部引用控制。
•PerThreadLifetimeManager - 为每个线程生成Singleton的对象实例,通过ThreadStatic实现。
•PerResolveLifetimeManager - 实现与TransientLifetimeManager类似的行为,为每次请求生成新的类型对象实例。不同之处在于对象实例在BuildUp过程中是可被重用的。
Code Double


代码如下:

public interface IExample : IDisposable
    {
      void SayHello();
    }

public class Example : IExample
    {
      private bool _disposed = false;
      private readonly Guid _key = Guid.NewGuid();

public void SayHello()
      {
        if (_disposed)
        {
          throw new ObjectDisposedException("Example",
              string.Format("{0} is already disposed!", _key));
        }

Console.WriteLine("{0} says hello in thread {1}!", _key,
            Thread.CurrentThread.ManagedThreadId);
      }

public void Dispose()
      {
        if (!_disposed)
        {
          _disposed = true;
        }
      }
    }

TransientLifetimeManager

TransientLifetimeManager是Unity默认的生存期管理器。其内部的实现都为空,这就意味着每次容器都会创建和返回一个新的对象实例,当然容器也不负责存储和销毁该对象实例。


代码如下:

private static void TestTransientLifetimeManager()
    {
      IExample example;
      using (IUnityContainer container = new UnityContainer())
      {
        container.RegisterType(typeof(IExample), typeof(Example),
          new TransientLifetimeManager());

// each one gets its own instance
        container.Resolve<IExample>().SayHello();
        example = container.Resolve<IExample>();
      }
      // container is disposed but Example instance still lives
      // all previously created instances weren't disposed!
      example.SayHello();

Console.ReadKey();
    }

ContainerControlledLifetimeManager

ContainerControlledLifetimeManager将为UnityContainer及其子容器提供一个Singleton的注册类型对象实例。其只在第一次请求某注册类型时创建一个新的对象实例,该对象实例将被存储到生存期管理器中,并且一直被重用。当容器析构时,生存期管理器会调用RemoveValue将存储的对象销毁。

Singleton对象实例对应每个对象类型注册,如果同一对象类型注册多次,则将为每次注册创建单一的实例。


代码如下:

private static void TestContainerControlledLifetimeManager()
    {
      IExample example;
      using (IUnityContainer container = new UnityContainer())
      {
        container.RegisterType(typeof(IExample), typeof(Example),
          new ContainerControlledLifetimeManager());

IUnityContainer firstSub = null;
        IUnityContainer secondSub = null;

try
        {
          firstSub = container.CreateChildContainer();
          secondSub = container.CreateChildContainer();

// all containers share same instance
          // each resolve returns same instance
          firstSub.Resolve<IExample>().SayHello();

// run one resolving in other thread and still receive same instance
          Thread thread = new Thread(
            () => secondSub.Resolve<IExample>().SayHello());
          thread.Start();

container.Resolve<IExample>().SayHello();
          example = container.Resolve<IExample>();
          thread.Join();
        }
        finally
        {
          if (firstSub != null) firstSub.Dispose();
          if (secondSub != null) secondSub.Dispose();
        }
      }

try
      {
        // exception - instance has been disposed with container
        example.SayHello();
      }
      catch (ObjectDisposedException ex)
      {
        Console.WriteLine(ex.Message);
      }

Console.ReadKey();
    }

HierarchicalLifetimeManager类衍生自ContainerControlledLifetimeManager,其继承了父类的所有行为。与父类的不同之处在于子容器中的生存期管理器行为。ContainerControlledLifetimeManager共享相同的对象实例,包括在子容器中。而HierarchicalLifetimeManager只在同一个容器内共享,每个子容器都有其单独的对象实例。


代码如下:

private static void TestHierarchicalLifetimeManager()
    {
      IExample example;
      using (IUnityContainer container = new UnityContainer())
      {
        container.RegisterType(typeof(IExample), typeof(Example),
          new HierarchicalLifetimeManager());

IUnityContainer firstSub = null;
        IUnityContainer secondSub = null;

try
        {
          firstSub = container.CreateChildContainer();
          secondSub = container.CreateChildContainer();

// each subcontainer has its own instance
          firstSub.Resolve<IExample>().SayHello();
          secondSub.Resolve<IExample>().SayHello();
          container.Resolve<IExample>().SayHello();
          example = firstSub.Resolve<IExample>();
        }
        finally
        {
          if (firstSub != null) firstSub.Dispose();
          if (secondSub != null) secondSub.Dispose();
        }
      }

try
      {
        // exception - instance has been disposed with container
        example.SayHello();
      }
      catch (ObjectDisposedException ex)
      {
        Console.WriteLine(ex.Message);
      }

Console.ReadKey();
    }

ExternallyControlledLifetimeManager

ExternallyControlledLifetimeManager中的对象实例的生存期限将有UnityContainer外部的实现控制。此生存期管理器内部直存储了所提供对象实例的一个WeakReference。所以如果UnityContainer容器外部实现中没有对该对象实例的强引用,则该对象实例将被GC回收。再次请求该对象类型实例时,将会创建新的对象实例。


代码如下:

private static void TestExternallyControlledLifetimeManager()
    {
      IExample example;
      using (IUnityContainer container = new UnityContainer())
      {
        container.RegisterType(typeof(IExample), typeof(Example),
          new ExternallyControlledLifetimeManager());

// same instance is used in following
        container.Resolve<IExample>().SayHello();
        container.Resolve<IExample>().SayHello();

// run garbate collector. Stored Example instance will be released
        // beacuse there is no reference for it and LifetimeManager holds
        // only WeakReference       
        GC.Collect();

// object stored targeted by WeakReference was released
        // new instance is created!
        container.Resolve<IExample>().SayHello();
        example = container.Resolve<IExample>();
      }

example.SayHello();

Console.ReadKey();
    }

这个结果证明强引用还存在,不知道为什么?如果你找到了原因,烦请告诉我,谢谢。

PerThreadLifetimeManager

PerThreadLifetimeManager模型提供“每线程单实例”功能。所有的对象实例在内部被存储在ThreadStatic的集合。容器并不跟踪对象实例的创建并且也不负责Dipose。


代码如下:

private static void TestPerThreadLifetimeManager()
    {
      IExample example;
      using (IUnityContainer container = new UnityContainer())
      {
        container.RegisterType(typeof(IExample), typeof(Example),
          new PerThreadLifetimeManager());

Action<int> action = delegate(int sleep)
        {
          // both calls use same instance per thread
          container.Resolve<IExample>().SayHello();
          Thread.Sleep(sleep);
          container.Resolve<IExample>().SayHello();
        };

Thread thread1 = new Thread((a) => action.Invoke((int)a));
        Thread thread2 = new Thread((a) => action.Invoke((int)a));
        thread1.Start(50);
        thread2.Start(50);

thread1.Join();
        thread2.Join();

example = container.Resolve<IExample>();
      }

example.SayHello();

Console.ReadKey();
    }

PerResolveLifetimeManager

PerResolveLifetimeManager是Unity内置的一个特殊的模型。因为Unity使用单独的逻辑来处理注册类型的Per-Resolve生命期。每次请求Resolve一个类型对象时,UnityContainer都会创建并返回一个新的对象实例。


代码如下:

private static void TestPerResolveLifetimeManager()
    {
      IExample example;
      using (IUnityContainer container = new UnityContainer())
      {
        container.RegisterType(typeof(IExample), typeof(Example),
          new PerResolveLifetimeManager());

container.Resolve<IExample>().SayHello();
        container.Resolve<IExample>().SayHello();

example = container.Resolve<IExample>();
      }

example.SayHello();

Console.ReadKey();
    }

(0)

相关推荐

  • Unity3D中脚本的执行顺序和编译顺序

    事件函数的执行顺序 先说一下执行顺序吧. 官方给出的脚本中事件函数的执行顺序如下图: 我们可以做一个小实验来测试一下: 在Hierarchy视图中创建三个游戏对象,在Project视图中创建三条脚本,如下图所示,然后按照顺序将脚本绑定到对应的游戏对象上: 三条脚本的代码完全一样,只是做了一点名称上的区分: using UnityEngine;using System.Collections;public class Scring0 : MonoBehaviour{    void Awake()

  • unity3d发布apk在android虚拟机中运行的详细步骤(unity3d导出android apk)

    unity3d发布apk在android虚拟机中运行的详细步骤(unity3d导出android apk),总的流程分为以下6个步骤: 1.安装java_jdk 2.配置java环境变量 3.更新android的sdk 4.从Unity3d中发布出apk文件 5.创建android虚拟机并运行 6.将apk文件安装到android虚拟机中 (为方便新手,在下面对每个步骤的具体操作及可能遇到的问题详细提一下) 1.安装java_jdk 官网(www.java.com),免费,我安装的文件的名字是j

  • Unity3d发布IOS9应用时出现中文乱码的解决方法

    简单的说,解决方法就是批量修改NGUI的label字体,修复ios就删除arial引起的中文乱码 我们来看具体如何操作 static public void yaheifont() { uf = AssetDatabase.LoadAssetAtPath("Assets/yahei.prefab",typeof( UIFont)) as UIFont; UnityEngine.Object[] objs = Selection.GetFiltered (typeof(UnityEngi

  • 基于Unity容器中的对象生存期管理分析

    IoC容器的对象生存期管理 如果你一直在使用IoC容器,你可能已经使用过了一些对象生存期管理模型(Object Lifetime Management).通过对对象生存期的管理,将使对象的复用成为可能.同时其使容器可以控制如何创建和管理对象实例. Unity提供的对象生存期管理模型是通过从抽象类LifetimeManager的派生类来完成.Unity将为每个类型的注册创建生存期管理器.每当UnityContainer需要创建一个新的对象实例时,将首先检测该对象类型的生存期管理器,是否已有一个对象

  • SpringBoot 如何从容器中获取对象

    目录 如何从容器中获取对象 SpringBoot中的容器 容器功能 1.组件添加 2.原生配置文件引入(xml文件引入) 3.配置绑定 如何从容器中获取对象 有时候在项目中,我们会自己创建一些类,类中需要使用到容器中的一些类.方法是新建类并实现ApplicationContextAware 接口,在类中建立静态对象 ApplicationContext 对象,这个对象就如同xml配置中的 applicationContext.xml,容器中类都可以获取到. 例如@Service. @Compon

  • 普通对象使用spring容器中的对象的实现方法

    引语: 工作中有时候需要在普通的对象中去调用spring管理的对象,但是在普通的java对象直接使用@Autowired或者@Resource的时候会发现被注入的对象是null,会报空指针.我们可以简单的理解为spring是一个公司,它管理的对象就是它的员工,而普通的java对象是其他公司的员工,如果其他公司要找spring公司的员工一起共事没有经过spring公司的同意肯定是不行的. 解决方式: 方法一:如果这个普通对象可以被spring管理的话,最好是直接交给spring管理,这样sprin

  • javascript中cookie对象用法实例分析

    本文实例讲述了javascript中cookie对象用法.分享给大家供大家参考.具体如下: 属性 name          唯一必须设置的属性,表示cookie的名称 expires       指定cookie的存活周期,如不设置,浏览器关闭自动失效 path           决定cookie对于服务器对于其他网页的可用性,一般情况下,   cookie对同一目录下的所有页面都可用,当设置path属性后,cookie只对指定路径及子路径下的所有网页有效 domain           

  • java中response对象用法实例分析

    本文实例讲述了java中response对象用法.分享给大家供大家参考,具体如下: <jsp:forward>动作元素用于运行时在服务器端结束当前页面的执行,并从当前页面转向指定页面. 使用response对象的setHeader()方法可以设置页面的自动刷新时间间隔.实现每隔60秒重新加载本页面的语句为: 复制代码 代码如下: response.setHeader("refresh",60); 而实现3秒后浏览器加载新页面http://www.jb51.net的语句为:

  • 微信小程序使用setData修改数组中单个对象的方法分析

    本文实例讲述了微信小程序使用setData修改数组中单个对象的方法.分享给大家供大家参考,具体如下: 微信小程序已经出来挺久的时间了,之前只是在文档上粗略的看了一下,最近稍得空闲,便利用微信小程序平台写一个练手的项目,顺便学习一下小程序开发,感觉大体跟前端开发基本类似,但是因为是在微信的平台上运行,具体还是要根据小程序的规则来编写代码的,其中还是有部分的内容跟前端中常见的有所不同,于是接下来的博客里,也会顺手记录微信小程序开发过程中的一些坑,帮助后来的小程序开发者少踩一些坑,当然我踩的坑大部分都

  • Spring-IOC容器中的常用注解与使用方法详解

    Spring是什么? Spring是一个轻量级Java开发框架,最早有Rod Johnson创建,目的是为了解决企业级应用开发的业务逻辑层和其他各层的耦合问题.它是一个分层的JavaSE/JavaEE full-stack(一站式)轻量级开源框架,为开发Java应用程序提供全面的基础架构支持.Spring负责基础架构,因此Java开发者可以专注于应用程序的开发. 体系结构 核心容器(Core Container):Spring的核心容器是其他模块建立的基础,有Spring-core.Spring

  • 创建动态代理对象bean,并动态注入到spring容器中的操作

    使用过Mybatis的同学,应该都知道,我们只需要编写mybatis对应的接口和mapper XML文件即可,并不需要手动编写mapper接口的实现.这里mybatis就用到了JDK动态代理,并且将生成的接口代理对象动态注入到Spring容器中. 这里涉及到几个问题.也许有同学会有疑问,我们直接编写好类,加入@Component等注解不是可以注入了吗?或者在配置类(@Configuration)中直接声明该Bean类型不也可以注入吗? 但具体到mybatis,这里我们用的是接口.由于spring

  • 基于JavaScript将表单序列化类型的数据转化成对象的处理(允许对象中包含对象)

    表单序列化类型的数据是指url传递的数据的格式,形如"key=value&key=value&key=value"这样的key/value的键值对.一般来说使用jQuery的$.fn.serialize函数能达到这样的效果.如何将这样的格式转化为对象? 我们知道使用jQuery的$.fn.serializeArray函数得到的是一个如下结构的对象 [ { name: "startTime" value: "2015-12-02 00:00:

  • Python的Twisted框架中使用Deferred对象来管理回调函数

    首先抛出我们在讨论使用回调编程时的一些观点: 激活errback是非常重要的.由于errback的功能与except块相同,因此用户需要确保它们的存在.他们并不是可选项,而是必选项. 不在错误的时间点激活回调与在正确的时间点激活回调同等重要.典型的用法是,callback与errback是互斥的即只能运行其中一个. 使用回调函数的代码重构起来有些困难. Deferred Twisted使用Deferred对象来管理回调函数的序列.有些情况下可能要把一系列的函数关联到Deferred对象上,以便在

随机推荐