重要的参考资料http://www.cnblogs.com/xdp-gacl/p/4249939.html

谈谈对Spring IOC的理解

IOC概念(很重要)

项目
先引入AutoFac 和AutoFac MVC两个程序集到项目中
 
然后我们在MVC(UI层)的App_Start文件夹下创建一个AutoFacConfig.cs类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace FB.CMS.MvcSite.App_Start
{
using Autofac;
using Autofac.Integration.Mvc;
using System.Reflection;
using System.Web.Mvc; /// <summary>
/// 这个类是我自己定义的一个类,主要用初始化AutoFac容器的相关数据
/// </summary>
public class AutoFacConfig
{ public static void Register()
{
//初始化AutoFac的相关功能
/*
1.0 告诉AutoFac初始化数据仓储层FB.CMS.Repository.dll中所有类的对象实例。这些对象实例以其接口的形式保存在AutoFac容器中
2.0 告诉AutoFac初始化业务逻辑层FB.CMS.Services.dll中所有类的对象实例。这些对象实例以其接口的形式保存在AutoFac容器中
3.0 将MVC默认的控制器工厂替换成AutoFac的工厂
*/ //第一步: 构造一个AutoFac的builder容器
ContainerBuilder builder = new Autofac.ContainerBuilder(); //第二步:告诉AutoFac控制器工厂,控制器类的创建去哪些程序集中查找(默认控制器工厂是去扫描bin目录下的所有程序集)
//2.1 从当前运行的bin目录下加载FB.CMS.MvcSite.dll程序集
Assembly controllerAss = Assembly.Load("FB.CMS.MvcSite"); //2.2 告诉AutoFac控制器工厂,控制器的创建从controllerAss中查找(注意:RegisterControllers()方法是一个可变参数,如果你的控制器类的创建需要去多个程序集中查找的话,那么我们就再用Assembly controllerBss=Assembly.Load("需要的程序集名")加载需要的程序集,然后与controllerAss组成数组,然后将这个数组传递到RegisterControllers()方法中)
builder.RegisterControllers(controllerAss); //第三步:告诉AutoFac容器,创建项目中的指定类的对象实例,以接口的形式存储(其实就是创建数据仓储层与业务逻辑层这两个程序集中所有类的对象实例,然后以其接口的形式保存到AutoFac容器内存中,当然如果有需要也可以创建其他程序集的所有类的对象实例,这个只需要我们指定就可以了) //3.1 加载数据仓储层FB.CMS.Repository这个程序集。
Assembly repositoryAss = Assembly.Load("FB.CMS.Repository");
//3.2 反射扫描这个FB.CMS.Repository.dll程序集中所有的类,得到这个程序集中所有类的集合。
Type[] rtypes = repositoryAss.GetTypes();
//3.3 告诉AutoFac容器,创建rtypes这个集合中所有类的对象实例
builder.RegisterTypes(rtypes)
.AsImplementedInterfaces(); //指明创建的rtypes这个集合中所有类的对象实例,以其接口的形式保存 //3.4 加载业务逻辑层FB.CMS.Services这个程序集。
Assembly servicesAss = Assembly.Load("FB.CMS.Services");
//3.5 反射扫描这个FB.CMS.Services.dll程序集中所有的类,得到这个程序集中所有类的集合。
Type[] stypes = servicesAss.GetTypes();
//3.6 告诉AutoFac容器,创建stypes这个集合中所有类的对象实例
builder.RegisterTypes(stypes)
.AsImplementedInterfaces(); //指明创建的stypes这个集合中所有类的对象实例,以其接口的形式保存 //第四步:创建一个真正的AutoFac的工作容器
var container = builder.Build(); //我们已经创建了指定程序集的所有类的对象实例,并以其接口的形式保存在AutoFac容器内存中了。那么我们怎么去拿它呢?
//从AutoFac容器内部根据指定的接口获取其实现类的对象实例
//假设我要拿到IsysFunctionServices这个接口的实现类的对象实例,怎么拿呢?
//var obj = container.Resolve<IsysFunctionServices>(); //只有有特殊需求的时候可以通过这样的形式来拿。一般情况下没有必要这样来拿,因为AutoFac会自动工作(即:会自动去类的带参数的构造函数中找与容器中key一致的参数类型,并将对象注入到类中,其实就是将对象赋值给构造函数的参数) //第五步:将当前容器中的控制器工厂替换掉MVC默认的控制器工厂。(即:不要MVC默认的控制器工厂了,用AutoFac容器中的控制器工厂替代)此处使用的是将AutoFac工作容器交给MVC底层 (需要using System.Web.Mvc;)
DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); //我们知道控制器的创建是调用MVC默认的控制器工厂,默认的控制器工厂是调用控制器类的无参构造函数
//可是我们如果要使用AutoFac自动工厂,将对象通过构造函数注入类中,那么这个构造函数就需要带参数
//如果我们将控制器的无参构造函数删除,保留带参数的构造函数,MVC默认的控制器工厂来创建控制的时候
//就会去调用无参的构造函数,可是这时候发现没有无参的构造函数于是就报“没有为该对象定义无参数的构造函数”错误
//既然报错,那我们如果保留无参的构造函数,同时在声明一个带参数的构造函数是否可行呢?
//答案;行是行,但是创建控制器的时候,MVC默认的控制器工厂调用的是无参构造函数,它并不会去调用有参的构造函数
//这时候,我们就只能将AutoFac它的控制器工厂替换调用MVC默认的控制器工厂(控制器由AutoFac的控制器工厂来创建)
//而AutoFac控制器工厂在创建控制的时候只会扫描带参数的构造函数,并将对象注入到带参数的构造函数中
//AutofacDependencyResolver这个控制器工厂是继承了 IDependencyResolver接口的,而IDependencyResolver接口是MVC的东西
//MVC默认的控制器工厂名字叫:DefaultControllerFactory
//具体参考:http://www.cnblogs.com/artech/archive/2012/04/01/controller-activation-032.html }
}
}

然后我们在Global.asax文件中的Application_Start()方法中来调用这个类

using FB.CMS.MvcSite.App_Start;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing; namespace FB.CMS.MvcSite
{
// 注意: 有关启用 IIS6 或 IIS7 经典模式的说明,
// 请访问 http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{ AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles); //第一: 在网站一启动的时候就初始化AutoFac的相关功能
/*
1.0 告诉AutoFac初始化数据仓储层FB.CMS.Repository.dll中所有类的对象实例。这些对象实例以其接口的形式保存在AutoFac容器中
2.0 告诉AutoFac初始化业务逻辑层FB.CMS.Services.dll中所有类的对象实例。这些对象实例以其接口的形式保存在AutoFac容器中
3.0 将MVC默认的控制器工厂替换成AutoFac的工厂
*/ //具体做法就是我们去App_Start文件夹下创建一个AutoFacConfig类,具体实现什么功能去这个类中实现。然后再这里调用下这个类
AutoFacConfig.Register();
}
}
}
使用
Home控制器
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace FB.CMS.MvcSite.Controllers
{
using FB.CMS.IServices;
public class HomeController : Controller
{
IsysFunctionServices dal;
public HomeController(IsysFunctionServices dal) //依赖构造函数进行对象注入
{
this.dal = dal; //在构造函数中初始化HomeController控制器类的dal属性 (这个dal属性的类型是IsysFunctionServices)
} public ActionResult Index()
{
var a = dal.QueryWhere(r => r.fID > ).ToList(); //查询
return View();
}
}
}

用AutoFac 在一个控制器下通过构造函数,注入多个对象的时候,我们可以对BaseDal进行优化

BaseDal类 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace FB.CMS.Repository
{
using FB.CMS.IRepository;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq.Expressions;
using System.Runtime.Remoting.Messaging;
using System.Threading;
public class BaseDal<TEntity> : IBaseDal<TEntity> where TEntity : class
{
//BaseDbContext db = new BaseDbContext(); //对创建上下文容器类对象进行优化(原理:一个线程下我们只创建一个上下文容器类对象,然后保存到线程缓存当中去,当同一个线程过来的时候,就从线程缓存当中取上下文容器类对象)
public BaseDbContext db
{
get
{
//获取BaseDbContext的完全限定名,其实这个名字没什么特别的意义,仅仅是一个名字而已,也可以取别的名字的
string threadName = typeof(BaseDbContext).FullName;
//获取key为threadName的这个线程缓存(CallContext就是线程缓存容器类)
object dbObj = CallContext.GetData(threadName);
//如果key为threadName的线程缓存不存在
if (dbObj == null)
{
//创建BaseDbContext类的对象实例
dbObj = new BaseDbContext();
//将这个BaseDbContext类的对象实例保存到线程缓存当中(以键值对的形式进行保存的,我这就将key设为当前线程的完全限定名了)
CallContext.SetData(threadName, dbObj);
return dbObj as BaseDbContext;
}
return dbObj as BaseDbContext;
} }
DbSet<TEntity> _dbset;
public BaseDal()
{
this._dbset = db.Set<TEntity>(); //初始化
} #region 增加
public void AddEnity(TEntity model)
{
if (model == null)
{
throw new Exception("moddel不能为null");
}
this._dbset.Add(model); } #endregion #region 物理删除
/// <summary>
/// 删除
/// </summary>
/// <param name="model">实体类</param>
/// <param name="isaddedContext">是否物理删除</param>
public void DeleteEntity(TEntity model, bool isaddedContext)
{
if (model == null)
{
throw new Exception("DeleteEntity方法中的model不能为null");
}
//如果仅仅是逻辑删除的话,那我们只要调用编辑方法将标识为逻辑删除的那个字段修改为true就可以了。
if (isaddedContext == true)
{
this._dbset.Attach(model); }
this._dbset.Remove(model);
} #endregion #region 查寻
/// <summary>
/// 普通带条件查询
/// </summary>
/// <param name="where"></param>
/// <returns></returns>
public IQueryable<TEntity> QueryWhere(Expression<Func<TEntity, bool>> where)
{
return this._dbset.Where(where);
} /// <summary>
/// 连表查询
/// </summary>
/// <param name="where">连表查询的条件筛选查询</param>
/// <param name="tablesName">要做连表查询的所有表名集合</param>
/// <returns></returns>
public IQueryable<TEntity> QueryJoin(Expression<Func<TEntity, bool>> where, string[] tablesName)
{
if (tablesName == null || tablesName.Any() == false)
{
throw new Exception("连表查询最少也要一个表,所有QueryJoin方法中tablesName中最少也需要有一个表名");
} DbQuery<TEntity> query = this._dbset;
foreach (string tableName in tablesName)
{
//不断的连表,直到把tablesName里的所有表都连完
query = query.Include(tableName);
}
return query.Where(where); //然后对连表进行条件筛选查询
} /// <summary>
/// 带条件的分页查询
/// </summary>
/// <typeparam name="TKey">按哪个字段进行排序</typeparam>
/// <param name="pageindex">当前页</param>
/// <param name="pagesize">页大小</param>
/// <param name="rowCount">数据总条数</param>
/// <param name="order">排序</param>
/// <param name="where">筛选条件</param>
/// <returns></returns>
public IQueryable<TEntity> QueryByPage<TKey>(int pageindex, int pagesize, out int rowCount, Expression<Func<TEntity, TKey>> order, Expression<Func<TEntity, bool>> where)
{
//获取总条数
rowCount = this._dbset.Count(where); //建议将这个Where条件语句放在前面,如果你放到后面,分页的时候可能存在问题。
return this._dbset.Where(where).OrderByDescending(order).Skip((pageindex - ) * pagesize).Take(pagesize); } /// <summary>
/// 调用存储过程或执行SQL语句(但是我们不推荐执行sql语句)
/// </summary>
/// <typeparam name="TElement">
/// 因为存储过程返回的数据不一定就是TEntity这个实体,因为存储过返回的结果集有可能是自己拼接出来的,所以这个方法的返回结果
/// 为Lsit<TEntity>就不合适了。 这个 TElement是在调用的存储过程的时候传入的一个实体,此实体必须和调用的存储过程的返回结集
/// 中的字段名称保存一致(你这个存储过程返回有多个字段,那么你这个实体中就应该有多少个属性)
/// </typeparam>
/// <param name="sql">
/// 假设我创建了这么一个存储过程:
/// create proc proc_T_UserInfo_Paging2(@pageSize int,@currentPage int,@CountData )
/// 那现在我们调用这个存储过程,那么这个SQL语句的写法就是:
/// proc_T_UserInfo_Paging2 @pageSize int,@currentPage int,@CountData ///
/// </param>
/// <param name="prms">参数化查询的参数数组</param>
/// <returns></returns>
public List<TElement> RunProc<TElement>(string sql, params object[] prms)
{
return db.Database.SqlQuery<TElement>(sql, prms).ToList();
}
#endregion #region 编辑
/// <summary>
/// 编辑
/// </summary>
/// <param name="model">实体</param>
/// <param name="propertyNames">要编辑的的所有属性名称序列</param>
public void EditEntity(TEntity model, string[] propertyNames)
{
if (model == null)
{
throw new Exception("EditEntity方法中的参数model不能为null");
}
if (propertyNames.Any() == false || propertyNames == null)
{
throw new Exception("EditEntity方法中的参数propertyNames最少需要一个属性");
}
System.Data.Entity.Infrastructure.DbEntityEntry entry = db.Entry(model);
entry.State = System.Data.EntityState.Unchanged;
foreach (string item in propertyNames)
{
entry.Property(item).IsModified = true;
}
db.Configuration.ValidateOnSaveEnabled = false;
} #endregion #region 统一保存
public int SaveChanges()
{
return db.SaveChanges();
}
#endregion
}
}

Home控制器

直接在控制器中使用方式是

public ActionResult Index()
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<UserInfoSevices>(); //想拿到UserInfoSevices类的实例
builder.RegisterType<UserInfoRepository>().As<IUserInfoRepository>(); //与之关联的UserInfoRepository类也需要拿到,并转化成接口的形式保存
var aa = builder.Build().Resolve<UserInfoSevices>().QueryModel(r => r.Age > ); //在这里使用 return View();
}

AutoFac (控制反转IOC 与依赖注入DI)的更多相关文章

  1. 控制反转IOC与依赖注入DI

    理解 IOC  http://www.cnblogs.com/zhangchenliang/archive/2013/01/08/2850970.html IOC 相关实例      的http:// ...

  2. 控制反转(Ioc)和依赖注入(DI)

    控制反转IOC, 全称 “Inversion of Control”.依赖注入DI, 全称 “Dependency Injection”. 面向的问题:软件开发中,为了降低模块间.类间的耦合度,提倡基 ...

  3. iOS控制反转(IoC)与依赖注入(DI)的实现

    背景 最近接触了一段时间的SpringMVC,对其控制反转(IoC)和依赖注入(DI)印象深刻,此后便一直在思考如何使用OC语言较好的实现这两个功能.Java语言自带的注解特性为IoC和DI带来了极大 ...

  4. 轻松学,浅析依赖倒置(DIP)、控制反转(IOC)和依赖注入(DI) 依赖注入和控制反转的理解,写的太好了。

    轻松学,浅析依赖倒置(DIP).控制反转(IOC)和依赖注入(DI) 2017年07月13日 22:04:39 frank909 阅读数:14269更多 所属专栏: Java 反射基础知识与实战   ...

  5. 控制反转IOC与依赖注入DI【转】

    转自:http://my.oschina.net/1pei/blog/492601 一直对控制反转.依赖注入不太明白,看到这篇文章感觉有点懂了,介绍的很详细. 1. IoC理论的背景我们都知道,在采用 ...

  6. 【转载】浅析依赖倒置(DIP)、控制反转(IOC)和依赖注入(DI)

    原文地址 http://blog.csdn.net/briblue/article/details/75093382 写这篇文章的原因是这两天在编写关于 Dagger2 主题的博文时,花了大量的精力来 ...

  7. 控制反转IOC与依赖注入DI - 理论篇

    学无止境,精益求精 十年河东十年河西,莫欺少年穷 昨天是五一小长假归来上班的第一天,身体疲劳,毫无工作热情.于是就看看新闻,喝喝茶,荒废了一天 也就在昨天,康美同事张晶童鞋让我学习下IOC的理论及实现 ...

  8. 依赖倒置(DIP)、控制反转(IOC)和依赖注入(DI)

    原文: https://blog.csdn.net/briblue/article/details/75093382 写这篇文章的原因是这两天在编写关于 Dagger2 主题的博文时,花了大量的精力来 ...

  9. 20181123_控制反转(IOC)和依赖注入(DI)

    一.   控制反转和依赖注入: 控制反转的前提, 是依赖倒置原则, 系统架构时,高层模块不应该依赖于低层模块,二者通过抽象来依赖 (依赖抽象,而不是细节) 如果要想做到控制反转(IOC), 就必须要使 ...

随机推荐

  1. 20155312 张竞予 Exp 8 Web基础

    Exp 8 Web基础 目录 基础问题回答 (1)什么是表单 (2)浏览器可以解析运行什么语言. (3)WebServer支持哪些动态语言 实践过程记录 1.Web前端:HTML 2.Web前端jav ...

  2. Injection

    what java EE提供了注入机制,使您的对象能够获取对资源和其他依赖项的引用,而无需直接实例化它们.通过使用将字段标记为注入点的注释之一来装饰字段或方法,可以在类中声明所需的资源和其他依赖项.然 ...

  3. 2019.03.09 codeforces833B. The Bakery(线段树优化dp)

    传送门 线段树优化dpdpdp入门题. 要求把nnn个数分成kkk段,每段价值为里面不相同的数的个数,求所有段的价值之和最大值.n≤35000,k≤50n\le35000,k\le50n≤35000, ...

  4. Visual Studio Code 学习记录

    Visual Studio Code的官方文档可以学到很多知识,不只是vs code的用法,包括一些语言的入门 和一些概念等等.很好的文档. ※,user.settings.json中的一些配置说明: ...

  5. android-audioRecord

    android 录音功能 录音的大致流程,流程图可以在文件下载:mediarecord.vsdx 切换设备.谁去更新播放流,自动选择新的设备?流程?

  6. Eclipse项目里面看源码和文档

    Eclipse项目里面看源码 1.新建项目列表 2.进入struts2-core-2.3.20.jar,双击之后,看不到源码 3.右键struts2-core-2.3.20.jar,选择propert ...

  7. Leetcode 34 Find First and Last Position of Element in Sorted Array 解题思路 (python)

    本人编程小白,如果有写的不对.或者能更完善的地方请个位批评指正! 这个是leetcode的第34题,这道题的tag是数组,需要用到二分搜索法来解答 34. Find First and Last Po ...

  8. html5之上的图片处理

    在开发 H5 应用的时候碰到一个问题,应用只需要一张小的缩略图,而用户用手机上传的确是一张大图,手机摄像机拍的图片好几 M,这可要浪费很多流量. 像我这么为用户着想的程序员,绝对不会让这种事情发生的, ...

  9. 与其他相似软件对比,win10中个人助理conrtana具备哪些独特的功能

    目前,Cortana 可以回答各种口头问题,直接设置提醒,或者提供位置导航,并支持语音命令处理各项事务,而且随时间的推移学习更多内容,从而变得更加个性化和实用.简单而言,集成在 Edge 浏览器中的 ...

  10. Windows-WMI 事件 ID 10或0x80041003 死机 解药

    最近笔记本重复了好几次奇怪的现象,重启后进入桌面,然后死机,木有蓝屏. 后来在安全模式里查了事件,如下 日志名称:          Application 来源:            Micros ...