重要的参考资料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. JDK工具 javap

    javap -c [ClassName]  编译为汇编语言

  2. 编写shell脚本kill掉占用cpu超过90%以上的程序

    由于集群用户经常会不懂如何提交作业,将作业直接运行到登录节点上,这样导致登录节点的cpu及内存占用很大,导致其他用户甚至无法登录.所以就想到了一种解决方法,写一个shell脚本,常驻登录节点,监控cp ...

  3. sjms-2 创建型模式

    设计模式分类 创建型模式(5种):工厂方法模式.抽象工厂模式.创建者模式.原型模式.单例模式结构型模式(7种):适配器模式.桥模式.组合模式.装饰模式.外观模式.享元模式.代理模式行为型模式(11种) ...

  4. 安装mysqlclient的时候出现Microsoft Visual C++ 14.0 is required报错

    在安装mysqlclient的时候出现了以下报错: 解决办法: 1.到提示网址:https://visualstudio.microsoft.com/download/里面下载对应VC++版本安装后继 ...

  5. JAVA:简单添加菜单界面(swing)第二版

    环境:jdk1.8 package com.le.tool; import java.awt.Color; import java.awt.Container; import java.awt.Flo ...

  6. Java变成思想--多线程

    Executor :线程池 CatchedThreadPool:创建与所需数量相同的线程,在回收旧线程是停止创建新县城. FixedThreadPool:创建一定数量的线程,所有任务公用这些线程. S ...

  7. CSU1333最短路问题SPFA

    fastvj.rainng.com/contest/236779#problem/I Description: n个点m条路每条路 l,r,t:表示这条路开l秒,关r秒,通过要t秒,问你车辆从s到t最 ...

  8. 3-Fiddler修改请求或响应内容

    1.修改请求内容 方法一:设置请求前断点,修改请求后发送 1)设置断点 2)选中请求,在inspectors下修改请求内容 3)修改请求后,点击Break on Response按钮,进行请求的发送 ...

  9. .net反混淆脱壳工具de4dot的使用

    de4dot是一个开源的.net反混淆脱壳工具,是用C#编写的,介绍一下它的使用方法 首先 pushd 到de4dot.exe所在文件夹,然后调用 de4dot.exe  路径+dll名称 如果显示: ...

  10. Photon自定义加载Resource之外的资源

    PhotonNetwork.cs 结尾添加如下代码: #region >>> Photon自定义异步加载GameObject public delegate void CustomL ...