IOC的优点:

1. 依赖接口,而非实现,如下代码,

这样的好处就是,客户端根本不知道PersonService的存在,如果我们换一下IPersonService的实现,客户端不用任何修改,

说的简单一点:就是解耦。

说的专业一点,就涉及到这三个术语:

    依赖倒置原则(DIP)它转换了依赖,高层模块不依赖于低层模块的实现,而低层模块依赖于高层模块定义的接口

    控制反转(IoC):它为相互依赖的组件提供抽象,将依赖(低层模块)对象的获得交给第三方(系统)来控制,即依赖对象不在被依赖模块的类中直接通过new来获取

     依赖注入DI:它提供一种机制,将需要依赖(低层模块)对象的引用传递给被依赖(高层模块)对象,常用的注入方法有:构造器注入,属性注入。

    他们三个的关系,总结 一下: DIP是一种设计原则,IOC是一种设计模式,DI 是IoC的一种实现方式,用来反转依赖

    public interface IPersonService
{
void Show();
} public class PersonService: IPersonService
{
public void Show()
{
Console.WriteLine("This is PersonService");
}
}
static void Main(string[] args)
{ WindsorContainer container = WindsorInit.GetContainer(); var instance = container.Resolve<IPersonService>();
instance.Show(); Console.ReadKey();
}

ABP使用的是IOC框架是Castle Windsor, 例子中使用的也是,

项目需要引用:

public class WindsorInit
{
private static WindsorContainer _container; public static WindsorContainer GetContainer()
{
if (_container == null)
{
_container = new WindsorContainer();
_container.Install(FromAssembly.This()); }
return _container;
} public void CloseContext()
{
_container.Dispose();
}
}
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().InNamespace("CastleWindsor").WithService.DefaultInterfaces());
}
}

以上的例子,是基于控制台程序。如果是Asp.Net MVC,该如何做呢?

是不是要在controller的action中,通过container.Resolve<IPersonService>(); 这样的调用调取服务端方法,这样做是不是太笨了。

后来看了园子里 大内老A 的文章才明白 文章链接:http://www.cnblogs.com/artech/archive/2012/04/01/controller-activation-031.html

通过文章的介绍 再结合ABP的源码,再分析一下ABP的IOC是如何实现的:

首先要做的都是注册,ABP采用模块化设计,在每个模块中,都会对自己的模块内部需要注册的类就是注册:IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());

[DependsOn(typeof(AuditCoreModule), typeof(AbpAutoMapperModule))]
public class AuditApplicationModule : AbpModule
{
public override void PreInitialize()
{
Configuration.UnitOfWork.IsolationLevel = IsolationLevel.ReadCommitted; AuthorizationInterceptorRegistrar.Initialize(IocManager);
} public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}
/// <summary>
/// Adds a dependency registrar for conventional registration.
/// </summary>
/// <param name="registrar">dependency registrar</param>
public void AddConventionalRegistrar(IConventionalDependencyRegistrar registrar)
{
_conventionalRegistrars.Add(registrar);
} /// <summary>
/// Registers types of given assembly by all conventional registrars. See <see cref="AddConventionalRegistrar"/> method.
/// </summary>
/// <param name="assembly">Assembly to register</param>
public void RegisterAssemblyByConvention(Assembly assembly)
{
RegisterAssemblyByConvention(assembly, new ConventionalRegistrationConfig());
} /// <summary>
/// Registers types of given assembly by all conventional registrars. See <see cref="AddConventionalRegistrar"/> method.
/// </summary>
/// <param name="assembly">Assembly to register</param>
/// <param name="config">Additional configuration</param>
public void RegisterAssemblyByConvention(Assembly assembly, ConventionalRegistrationConfig config)
{
var context = new ConventionalRegistrationContext(assembly, this, config);

//你可以通过实现IConventionalRegisterer接口,写你自己的约定注册类,然后在你的模块的预初始化里,调用IocManager.AddConventionalRegisterer方法,添加你的类。
foreach (var registerer in _conventionalRegistrars)
{
registerer.RegisterAssembly(context);
} if (config.InstallInstallers)
{
IocContainer.Install(FromAssembly.Instance(assembly));
}
}
public class BasicConventionalRegistrar : IConventionalDependencyRegistrar
{
public void RegisterAssembly(IConventionalRegistrationContext context)
{
//Transient
context.IocManager.IocContainer.Register(
Classes.FromAssembly(context.Assembly)
.IncludeNonPublicTypes()
.BasedOn<ITransientDependency>()
.If(type => !type.GetTypeInfo().IsGenericTypeDefinition)
.WithService.Self()
.WithService.DefaultInterfaces()
.LifestyleTransient()
); //Singleton
context.IocManager.IocContainer.Register(
Classes.FromAssembly(context.Assembly)
.IncludeNonPublicTypes()
.BasedOn<ISingletonDependency>()
.If(type => !type.GetTypeInfo().IsGenericTypeDefinition)
.WithService.Self()
.WithService.DefaultInterfaces()
.LifestyleSingleton()
); //Windsor Interceptors
context.IocManager.IocContainer.Register(
Classes.FromAssembly(context.Assembly)
.IncludeNonPublicTypes()
.BasedOn<IInterceptor>()
.If(type => !type.GetTypeInfo().IsGenericTypeDefinition)
.WithService.Self()
.LifestyleTransient()
);
}
}

BasicConventionalRegistrar这个类非常重要,它利用casle windsor的注册方法,将我们实现了ITransientDependency,ISingletonDependency,IInterceptor的类进行注册

还要注意 DefaultInterfaces方法,看下它的注释:就是说我们注册的PersonService,它的默认接口就是IPersonService,这么当我们通过IOCManager解析IPersonService时,就会返回PersonService的实例。

        //
// 摘要:
// Uses all interfaces that have names matched by implementation type name. Matches
// Foo to IFoo, SuperFooExtended to IFoo and IFooExtended etc
public BasedOnDescriptor DefaultInterfaces();

以上这个类BasicConventionalRegistrar是通过如下代码,添加到 IocManager.AddConventionalRegistrar(new BasicConventionalRegistrar());

public sealed class AbpKernelModule : AbpModule
{
public override void PreInitialize()
{
IocManager.AddConventionalRegistrar(new BasicConventionalRegistrar()); IocManager.Register<IScopedIocResolver, ScopedIocResolver>(DependencyLifeStyle.Transient);
IocManager.Register(typeof(IAmbientScopeProvider<>), typeof(DataContextAmbientScopeProvider<>), DependencyLifeStyle.Transient); AddAuditingSelectors();
AddLocalizationSources();
AddSettingProviders();
AddUnitOfWorkFilters();
ConfigureCaches();
AddIgnoredTypes();
}
....
}

就这样,ABP自动注册所有 Repositories, Domain Services, Application Services, MVC 控制器和Web API控制器(前提是你都实现ITransientDependency或ISingletonDependency)

自定义/直接 注册

如果之前描述的方法还是不足以应对你的情况,你可以使用Castle Windsor注册类和及依赖项。因此,您将拥有Castle Windsor注册的所有能力。

可以实现IWindsorInstaller接口进行注册。您可以在应用程序中创建一个实现IWindsorInstaller接口的类:

public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().InNamespace("CastleWindsor").WithService.DefaultInterfaces());
}
}

Abp自动发现和执行这个类。最后,你可以通过使用IIocManager.IocContainer属性得到WindsorContaine。

如果只想注册一个类,又不写这样的installer,可以使用

public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
IocManager.Register(
Component.For<IPersonRepository>().ImplementedBy<PersonRepository>().LifestyleTransient(),
Component.For<IPersonAppService>().ImplementedBy<PersonAppService>().LifestyleTransient() );
}

注册的三种方式,就说完了,又回到刚才的问题,我们在controller里是如何获取服务层的实例呢,服务层可以通过属性注入,或者构造器注入,其实在controller层也是通过这两种注册方式获取服务层的实例的,但mvc是如何创建出这个controller,然后通过IOC容器创建出服务层的实例呢?结合老A的文章,能够很快的找个继承DefaultControllerFactory类的 WindsorControllerFactory。 我们看下ABP是如何做的:

[DependsOn(typeof(AbpWebModule))]
public class AbpWebMvcModule : AbpModule
{
..............................
/// <inheritdoc/>
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
//就是这句
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(IocManager));
HostingEnvironment.RegisterVirtualPathProvider(IocManager.Resolve<EmbeddedResourceVirtualPathProvider>());
}
.....................
}
/// <summary>
/// This class is used to allow MVC to use dependency injection system while creating MVC controllers.
/// </summary>
public class WindsorControllerFactory : DefaultControllerFactory
{
/// <summary>
/// Reference to DI kernel.
/// </summary>
private readonly IIocResolver _iocManager; /// <summary>
/// Creates a new instance of WindsorControllerFactory.
/// </summary>
/// <param name="iocManager">Reference to DI kernel</param>
public WindsorControllerFactory(IIocResolver iocManager)
{
_iocManager = iocManager;
} /// <summary>
/// Called by MVC system and releases/disposes given controller instance.
/// </summary>
/// <param name="controller">Controller instance</param>
public override void ReleaseController(IController controller)
{
_iocManager.Release(controller);
} /// <summary>
/// Called by MVC system and creates controller instance for given controller type.
/// </summary>
/// <param name="requestContext">Request context</param>
/// <param name="controllerType">Controller type</param>
/// <returns></returns>
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return base.GetControllerInstance(requestContext, controllerType);
} return _iocManager.Resolve<IController>(controllerType);
}
}

ABP 源码分析汇总之 IOC的更多相关文章

  1. ABP 源码分析汇总之 AutoMapper

    AutoMapper 是一个对象映射工具, 安装时只需要安装 如下即可: 有关于它的介绍,参考官网:http://automapper.org/ AutoMapper使用比较简单,还是直奔主题,看一下 ...

  2. ABP源码分析二十:ApplicationService

    IApplicationService : 空接口,起标识作用.所有实现了IApplicationService 的类都会被自动注入到容器中.同时所有IApplicationService对象都会被注 ...

  3. [Abp 源码分析]三、依赖注入

    0.简要介绍 在 Abp 框架里面,无时无刻不存在依赖注入,关于依赖注入的作用与好处我就不在这里多加赘述了,网上有很多解释的教程.在 [Abp 源码分析]一.Abp 框架启动流程分析 里面已经说过,A ...

  4. [Abp 源码分析]十七、ASP.NET Core 集成

    0. 简介 整个 Abp 框架最为核心的除了 Abp 库之外,其次就是 Abp.AspNetCore 库了.虽然 Abp 本身是可以用于控制台程序的,不过那样的话 Abp 就基本没什么用,还是需要集合 ...

  5. 使用react全家桶制作博客后台管理系统 网站PWA升级 移动端常见问题处理 循序渐进学.Net Core Web Api开发系列【4】:前端访问WebApi [Abp 源码分析]四、模块配置 [Abp 源码分析]三、依赖注入

    使用react全家桶制作博客后台管理系统   前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基 ...

  6. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  7. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

  8. ABP源码分析三:ABP Module

    Abp是一种基于模块化设计的思想构建的.开发人员可以将自定义的功能以模块(module)的形式集成到ABP中.具体的功能都可以设计成一个单独的Module.Abp底层框架提供便捷的方法集成每个Modu ...

  9. ABP源码分析四:Configuration

    核心模块的配置 Configuration是ABP中设计比较巧妙的地方.其通过AbpStartupConfiguration,Castle的依赖注入,Dictionary对象和扩展方法很巧妙的实现了配 ...

随机推荐

  1. LInux进程虚拟地址空间的管理

    2017-04-07 脱离物理内存的管理,今天咱们来聊聊进程虚拟内存的管理.因为进程直接分配和使用的都是虚拟内存,而物理内存则是有系统“按需”分配给进程,在进程看来,只知道虚拟内存的存在! 前言: 关 ...

  2. Python用MySQLdb, pymssql 模块通过sshtunnel连接远程数据库

    转载自 https://www.cnblogs.com/luyingfeng/p/6386093.html 安全起见,数据库的访问多半是要做限制的,所以就有一个直接的问题是,往往多数时候,在别的机器上 ...

  3. 从CPU/OS到虚拟机和云计算

      从CPU/OS到虚拟机和云计算  作者:张冬            关于软硬件谁为主导这个话题,套用一句谚语就是三十年河东三十年河西.风水轮流转.软件和硬件一定是相互促进.相互拆台又相互搭台的. ...

  4. Windows服务的安装、卸载

    创建一个Windows服务 http://jingyan.baidu.com/article/fa4125acb71a8628ac709226.html 安装服务 使用FramWork框架自带的Ins ...

  5. Linux SSH免登录配置总结(转)

    转载请出自出处:http://eksliang.iteye.com/blog/2187265 一.原理 我们使用ssh-keygen在ServerA上生成私钥跟公钥,将生成的公钥拷贝到远程机器Serv ...

  6. POJ2480:Longge's problem(欧拉函数的应用)

    题目链接:传送门 题目需求: Given an integer N(1 < N < 2^31),you are to calculate ∑gcd(i, N) 1<=i <=N ...

  7. Java 语言中 Enum 类型的使用介绍【转载】

    简介:本文主要介绍了 Java 语言中枚举类型,以及如何定制 Enum 类型的定义,如何正确使用 Enum 类型. From:http://www.ibm.com/developerworks/cn/ ...

  8. 8种主要排序算法的C#实现 (一)

    简介 排序算法是我们编程中遇到的最多的算法.目前主流的算法有8种. 平均时间复杂度从高到低依次是: 冒泡排序(o(n2)),选择排序(o(n2)),插入排序(o(n2)),堆排序(o(nlogn)), ...

  9. H5端js实现图片放大滑动查看-插件photoswipe的使用

    最近在开发项目的时候,遇到一个需求,需要移动端实现放大查看图片的功能,然后我就在网上搜索了一下资料,看到了photoswipe这个插件,后来试了试,确实挺好用的,它可以实现手势放大缩小查看图片,左右滑 ...

  10. gitHub新项目的上传

    github作为一个开源托管平台,除了有机会学习各位大神的开源项目,还能托管自己写的一些小Demo,作为github新进菜鸟,今天就整理下上传Demo所需的命令和操作步骤,防止我这谜一样的记忆力. 1 ...