1.引言 

前面几个章节介绍了Unity的基本使用,主要分为程序和配置文件两种方法的使用,可以参考一下链接,

本节作为结束篇,将介绍一下在项目中如何应用Unity。   

2.范例

Unity应用广泛,在很多开源项目中都可以找到Unity的身影。就拿微软的开源项目新闻发布系统 Kigg 举例,Kigg的依赖注入就是使用到了Unity,大家可以下载。Kigg是MVC应用的一个推荐范例,本节介绍一下其中的依赖注入IoC容器,该容器在Kigg.Core项目,Infrastructure目录下的IOC目录,该目录下有4个类,如下图

先看看 IDependencyResolver 接口声明

IDependencyResolver 声明

    public interface IDependencyResolver : IDisposable
{
/// <summary>
/// 注册 T类型实例
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="instance"></param>
void Register<T>(T instance); /// <summary>
/// 注入
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="existing"></param>
void Inject<T>(T existing); /// <summary>
/// 解析
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="type"></param>
/// <returns></returns>
T Resolve<T>(Type type); T Resolve<T>(Type type, string name); T Resolve<T>(); T Resolve<T>(string name); IEnumerable<T> ResolveAll<T>();
}

看到该接口定义,我们很快会想到Unity中的IUnityContainer容器接口,对的,里面的方法和作用 跟IUnityContainer接口类似。
那为什么不直接使用IUnityContainer而要定义一个类似的接口IDependencyResolver呢? 
可以看到Kigg的IDependencyResolver是定义在核心层Kigg.Core相当于基础架构层中,而这个层是一个核心库,其它层都会引用它,Kigg应用了一种像 适配器模式来进行封装。
就是系统中要应用其它的外部接口,比如Unity 和Sping.net的依赖注入的方法不统一,我们要进行封装,可以先定义一个公共接口,再利用Unity和其它组件来实现它,这就是IDependencyResolver的由来。

Kigg中已经利用Unity来实现IDependencyResolver接口,当然我们也可以用其他的依赖注入容器来实现它,下面看看UnityDependencyResolver的实现

UnityDependencyResolver 声明

public class UnityDependencyResolver : DisposableResource, IDependencyResolver
{
//注入容器
private readonly IUnityContainer _container; [DebuggerStepThrough]
public UnityDependencyResolver() : this(new UnityContainer())
{
UnityConfigurationSection configuration = (UnityConfigurationSection) ConfigurationManager.GetSection("unity");
configuration.Containers.Default.Configure(_container);
} [DebuggerStepThrough]
public UnityDependencyResolver(IUnityContainer container)
{
Check.Argument.IsNotNull(container, "container"); _container = container;
} [DebuggerStepThrough]
public void Register<T>(T instance)
{
Check.Argument.IsNotNull(instance, "instance");
//注册实例
_container.RegisterInstance(instance);
} [DebuggerStepThrough]
public void Inject<T>(T existing)
{
Check.Argument.IsNotNull(existing, "existing");
//注入加载
_container.BuildUp(existing);
} [DebuggerStepThrough]
public T Resolve<T>(Type type)
{
Check.Argument.IsNotNull(type, "type");
//解析
return (T) _container.Resolve(type);
} [DebuggerStepThrough]
public T Resolve<T>(Type type, string name)
{
Check.Argument.IsNotNull(type, "type");
Check.Argument.IsNotEmpty(name, "name"); return (T) _container.Resolve(type, name);
} [DebuggerStepThrough]
public T Resolve<T>()
{
return _container.Resolve<T>();
} [DebuggerStepThrough]
public T Resolve<T>(string name)
{
Check.Argument.IsNotEmpty(name, "name"); return _container.Resolve<T>(name);
} [DebuggerStepThrough]
public IEnumerable<T> ResolveAll<T>()
{
//解析容器中所有
IEnumerable<T> namedInstances = _container.ResolveAll<T>();
T unnamedInstance = default(T); try
{
unnamedInstance = _container.Resolve<T>();
}
catch (ResolutionFailedException)
{
//When default instance is missing
} if (Equals(unnamedInstance, default(T)))
{
return namedInstances;
} return new ReadOnlyCollection<T>(new List<T>(namedInstances) { unnamedInstance });
} [DebuggerStepThrough]
protected override void Dispose(bool disposing)
{
if (disposing)
{
_container.Dispose();
} base.Dispose(disposing);
}
}

可以看到UnityDependencyResolver的默认构造函数是加载配置文件(配置文件在Web.Config中)来初始化IUnityContainer,你也可以用编程的方式。
实现方式中没有继承IUnityContainer或者UnityContainer,而是和IUnityContainer是组合关系,这样更加的灵活,这是对象的Adapter模式,就是组合模式。如果有其它的IoC容器,如Windsor/StructureMap/Spring.Net等等,可以实现IDependencyResolver接口即可。

使用时,只需要实例化对应的IDependencyResolver对象就可以了,Kigg中为了更好的控制IDependencyResolver对象的创建,利用了工厂方法来创建。
先看看工厂接口IDependencyResolverFactory

IDependencyResolverFactory定义

    public interface IDependencyResolverFactory
{
/// <summary>
/// 创建IDependencyResolver的实例
/// </summary>
/// <returns></returns>
IDependencyResolver CreateInstance();
}

看到定义,只有一个方法CreateInstance,就是用来创建IDependencyResolver对象,我们可以实现该工厂,可以直接new UnityDependencyResolver来创建,Kigg中利用配置文件方式,看DependencyResolverFactory的声明如下:

DependencyResolverFactory 定义

    public class DependencyResolverFactory : IDependencyResolverFactory
{
private readonly Type _resolverType; public DependencyResolverFactory(string resolverTypeName)
{
Check.Argument.IsNotEmpty(resolverTypeName, "resolverTypeName");
//GetType(名字,是否区分大小,是否异常)
_resolverType = Type.GetType(resolverTypeName, true, true);
} public DependencyResolverFactory() : this(new ConfigurationManagerWrapper().AppSettings["dependencyResolverTypeName"])
{
} public IDependencyResolver CreateInstance()
{
//根据类型创建实例对象
return Activator.CreateInstance(_resolverType) as IDependencyResolver;
}
}

可以看到默认构造函数是读取配置文件dependencyResolverTypeName节点,利用反射Activator.CreateInstance进行创建,看看dependencyResolverTypeName节点定义,在Kigg.Web项目的配置文件中,如下:

    <appSettings>
<clear/>
<add key="dependencyResolverTypeName" value="Kigg.Infrastructure.EnterpriseLibrary.UnityDependencyResolver, Kigg.Infrastructure.EnterpriseLibrary"/>
</appSettings>

还有其它IoC容器实现时,只要更改配置文件就行。

使用时可以调用工厂方法进行创建IDependencyResolver对象,每次使用时都得利用工厂来创建,IDependencyResolver里面的方法肯定都是实例方法,使用也不方便,Kigg为我们进行封装成静态方法,看IoC类的声明

IoC 定义

 public static class IoC
{
//解析器
private static IDependencyResolver _resolver; /// <summary>
/// 初始化,创建实例对象
/// </summary>
/// <param name="factory"></param>
[DebuggerStepThrough]
public static void InitializeWith(IDependencyResolverFactory factory)
{
Check.Argument.IsNotNull(factory, "factory"); _resolver = factory.CreateInstance();
} /// <summary>
/// 注册对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="instance"></param>
[DebuggerStepThrough]
public static void Register<T>(T instance)
{
Check.Argument.IsNotNull(instance, "instance"); _resolver.Register(instance);
} /// <summary>
/// 注入对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="existing"></param>
[DebuggerStepThrough]
public static void Inject<T>(T existing)
{
Check.Argument.IsNotNull(existing, "existing"); _resolver.Inject(existing);
} /// <summary>
/// 解析对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="type"></param>
/// <returns></returns>
[DebuggerStepThrough]
public static T Resolve<T>(Type type)
{
Check.Argument.IsNotNull(type, "type"); return _resolver.Resolve<T>(type);
}
/// <summary>
/// 解析对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="type"></param>
/// <param name="name"></param>
/// <returns></returns>
[DebuggerStepThrough]
public static T Resolve<T>(Type type, string name)
{
Check.Argument.IsNotNull(type, "type");
Check.Argument.IsNotEmpty(name, "name"); return _resolver.Resolve<T>(type, name);
}
/// <summary>
/// 解析对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[DebuggerStepThrough]
public static T Resolve<T>()
{
return _resolver.Resolve<T>();
}
/// <summary>
/// 解析对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name"></param>
/// <returns></returns>
[DebuggerStepThrough]
public static T Resolve<T>(string name)
{
Check.Argument.IsNotEmpty(name, "name"); return _resolver.Resolve<T>(name);
}
/// <summary>
/// 解析对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[DebuggerStepThrough]
public static IEnumerable<T> ResolveAll<T>()
{
return _resolver.ResolveAll<T>();
}
/// <summary>
/// 销毁
/// </summary>
[DebuggerStepThrough]
public static void Reset()
{
if (_resolver != null)
{
_resolver.Dispose();
}
}
}

IDependencyResolver是IoC的一个私有静态成员,私有的,那怎么创建对象,IoC类有一个InitializeWith(IDependencyResolverFactory factory),利用工厂方法来创建,以后我们只要使用IoC这个类就行。IoC静态类并没有在静态构造函数中初始化IDependencyResolver,考虑到依赖,只依赖比较稳定的接口,而不会依赖具体的实现如DependencyResolverFactory,这样就可以提供方法供外面访问来进行创建IDependencyResolver对象。

那IDependencyResolver什么时候会创建,由于没有在构造函数中实现创建,必定要调用IoC的InitializeWith方法,我们可以找到引用,看到一个启动引导Bootstrapper类如下:

Bootstrapper定义

    public static class Bootstrapper
{
static Bootstrapper()
{
try
{
IoC.InitializeWith(new DependencyResolverFactory());
}
catch (ArgumentException)
{
// Config file is Missing
}
} public static void Run()
{
IoC.ResolveAll<IBootstrapperTask>().ForEach(t => t.Execute());
}
}

在Bootstrapper的构造函数中进行了IDependencyResolver的创建,即在第一次使用Bootstrapper时会创建,那肯定的是Bootstrapper一定要在IoC之前使用啊,不然在使用IoC类时肯定报错,不用担心,Bootstrapper使用的很早,因为它是一个引导启动类,查找引用,可以看到在Kigg.Web下的Global.asax文件中找到,声明如下

GlobalApplication 定义

    public class GlobalApplication : HttpApplication
{ public static void OnStart()
{
Bootstrapper.Run();
Log.Info("Application Started");
} public static void OnEnd()
{
Log.Warning("Application Ended");
IoC.Reset();
} protected void Application_Start()
{
OnStart();
} protected void Application_End()
{
OnEnd();
}
}

原来在Application_Start中,程序启动时就使用到了,好了,以后就直接使用Ioc来创建依赖对象吧,不用new了,Unity的配置文件都是在Web.Config中,就不介绍了,Kigg的依赖容器就介绍完毕了。

3.小结

我们使用时如果想要IoC容器容易扩展容易使用可以参照Kigg。

IUnityContainer容器可以声明N个对象,那样就不好管理了,我们应该只要一个,即创建一次,可以使用static静态成员。

不用担心一个IUnityContainer容器中注册了太多对象关系而影响解析性能,IUnityContainer中是维护着许多字典,就是说注册100个跟注册100W个映射是一样的。

IUnityContainer可以通过编程映射和配置文件映射,推荐配置文件映射。

[IoC容器Unity]第四回:使用范例的更多相关文章

  1. [IoC容器Unity]第三回:依赖注入

    1.引言 上节介绍了,Unity的Lifetime Managers生命周期,Unity具体实现依赖注入包含构造函数注入.属性注入.方法注入,所谓注入相当赋值,下面一个一个来介绍. 2.构造函数注入 ...

  2. IOC容器Unity的使用及独立配置文件Unity.Config

    [本段摘录自:IOC容器Unity 使用http://blog.csdn.net/gdjlc/article/details/8695266] 面向接口实现有很多好处,可以提供不同灵活的子类实现,增加 ...

  3. [IoC容器Unity]第一回:Unity预览

    1.引言 高内聚,低耦合成为一个OO架构设计的一个参考标准.高内聚是一个模块或者一个类中成员跟这个模块或者类的关系尽量高,低耦合是不同模块或者不同类之间关系尽量简单. 拿咱国家举例来说,假如你是中国人 ...

  4. [IoC容器Unity] :Unity预览

    1.引言 高内聚,低耦合成为一个OO架构设计的一个参考标准.高内聚是一个模块或者一个类中成员跟这个模块或者类的关系尽量高,低耦合是不同模块或者不同类之间关系尽量简单. 拿咱国家举例来说,假如你是中国人 ...

  5. 【spring源码分析】IOC容器初始化(四)

    前言:在[spring源码分析]IOC容器初始化(三)中已经分析了BeanDefinition注册之前的一些准备工作,下面将进入BeanDefinition注册的核心流程. //DefaultBean ...

  6. [IoC容器Unity]第二回:Lifetime Managers生命周期

    1.引言 Unity的生命周期是注册的类型对象的生命周期,而Unity默认情况下会自动帮我们维护好这些对象的生命周期,我们也可以显示配置对象的生命周期,Unity将按照配置自动管理,非常方便,下面就介 ...

  7. [转载][IoC容器Unity]第二回:Lifetime Managers生命周期

    1.引言 Unity的生命周期是注册的类型对象的生命周期,而Unity默认情况下会自动帮我们维护好这些对象的生命周期,我们也可以显示配置对象的生命周期,Unity将按照配置自动管理,非常方便,下面就介 ...

  8. 微软IOC容器Unity简单代码示例3-基于约定的自动注册机制

    @(编程) [TOC] Unity在3.0之后,支持基于约定的自动注册机制Registration By Convention,本文简单介绍如何配置. 1. 通过Nuget下载Unity 版本号如下: ...

  9. 微软IOC容器Unity简单代码示例2-配置文件方式

    @(编程) 1. 通过Nuget下载Unity 这个就不介绍了 2. 接口代码 namespace UnityDemo { interface ILogIn { void Login(); } } n ...

随机推荐

  1. 007-chrome插件系列

    1.Axure RP Extension for Chrome 2.Charset 3.CLEAN crxMouse Gestures 4.Google 翻译 5.JSONView 6.restlet

  2. bios下能看到硬盘,进入系统看不到的解决方法

    新加了个固态硬盘 安装完系统后,打开我的电脑 看不到老硬盘的分区,进入磁盘管理也看不到. 最后,重启 选择老硬盘进入系统后, 再重启,进入新硬盘的系统, 就显示出来了

  3. Angular7上手体验

    准备工具 Node.js Angular requires Node.js version 8.x or 10.x. 查看当前你的node版本可以在CMD中输入 node -v npm -v 开发工具 ...

  4. Ubuntu server LTS 16.04安装SSH以及连接问题

    1.SSH安装 出现问题: 登录到Ubuntu服务器,执行以下命令: sudo apt-get install openssh-server 出现以下错误: 解决办法: 1)确保服务器能出外网,比如说 ...

  5. JS对象、构造器函数和原型对象之间的关系

    一.基本概念 1.对象:属性和方法的集合,即变量和函数的封装.每个对象都有一个__proto__属性,指向这个对象的构造函数的原型对象. 2.构造器函数:用于创建对象的函数,通过new关键字生成对象. ...

  6. 关于iframe的一些操作

    用于自己学习,本身对于js的一些东西没有深入了解,也是用到再去查 1.如果现在在一个页面,想要获取这个页面中的iframe中嵌入的页面中的一个指定id的div var iframeObj = docu ...

  7. PAT (Basic Level) Practice (中文)1001 害死人不偿命的(3n+1)猜想

    1001 害死人不偿命的(3n+1)猜想 卡拉兹(Callatz)猜想: 对任何一个正整数 n,如果它是偶数,那么把它砍掉一半:如果它是奇数,那么把 (3n+1) 砍掉一半.这样一直反复砍下去,最后一 ...

  8. PAT (Basic Level) Practice (中文)1023 组个最小数

    1023 组个最小数 给定数字 0-9 各若干个.你可以以任意顺序排列这些数字,但必须全部使用.目标是使得最后得到的数尽可能小(注意 0 不能做首位).例如:给定两个 0,两个 1,三个 5,一个 8 ...

  9. 华为AR-111S路由器GRE协议设置

    一.GRE的定义: gre(generic routing encapsulation,通用路由封装)协议是对某些网络层协议(如ip 和ipx)的数据报进行封装,使这些被封装的数据报能够在另一个网络层 ...

  10. Lua 哑变量

    [1]哑变量 哑变量,又称为虚拟变量.名义变量. 还得理解汉语的博大精深,‘虚拟’.‘名义’.‘哑’等等,都是没有实际意义.所以,哑变量即没有现实意义的变量. 哑变量的应用示例如下: local fi ...