1.)在使用IOC之前误甚,先談?wù)勈裁词荌OC?
IOC是Inversion of Control的縮寫-“控制反轉(zhuǎn)”宪萄。
解耦圖.png
通過上圖,由于引進了中間位置的第三方屎债,也就是IOC容器仅政,使得A、B盆驹、C圆丹、D這4個對象沒有了耦合的關(guān)系,所有的對象都由容器進行管理召娜,這樣也可以看出對象A獲得依賴對象B的過程运褪,由主動變成被動-(控制反轉(zhuǎn))惊楼。
2.)如何通過IOC容器創(chuàng)建實例玖瘸?
IOC容器是通過反射進行創(chuàng)建實例,而對IOC的具體實現(xiàn)的框架有多種檀咙,當然也可以自己封裝一套自己的容器雅倒,而今天主要介紹的是Unity容器。
通過NuGet導入Unity包:
Unity包.png
創(chuàng)建一個Unity容器:
IUnityContainer unityContainer = new UnityContainer();
注冊對象:
//IPhone-抽象
//AndroidPhone-具體實現(xiàn)
unityContainer.RegisterType<IPhone, AndroidPhone>();
獲取對象的實例:
IPhone phone = unityContainer.Resolve<IPhone>();
3.)Unity生命周期
默認瞬時生命周期:每次返回都是一個新的對象弧可。
container.RegisterType<AbstractPad, ApplePad>(new TransientLifetimeManager());
AbstractPad Pad1 = container.Resolve<AbstractPad>();
AbstractPad Pad2 = container.Resolve<AbstractPad>();
Console.WriteLine(object.ReferenceEquals(Pad1, Pad2));
單例生命周期:每次返回都是同一個對象蔑匣。
container.RegisterType<AbstractPad, ApplePad>(new SingletonLifetimeManager());
AbstractPad pad1 = container.Resolve<AbstractPad>();
AbstractPad pad2 = container.Resolve<AbstractPad>();
Console.WriteLine(object.ReferenceEquals(pad1, pad2));
線程單例生命周期:同一個線程就只有一個實例,不同線程就是不同實例。
container.RegisterType<AbstractPad, ApplePad>(new PerThreadLifetimeManager());
AbstractPad pad1 = null;
AbstractPad pad2 = null;
AbstractPad pad3 = null;
Action act1 = new Action(() =>
{
pad1 = container.Resolve<AbstractPad>();
Console.WriteLine($"pad1由線程id={Thread.CurrentThread.ManagedThreadId}");
});
var result1 = act1.BeginInvoke(null, null);
Action act2 = new Action(() =>
{
pad2 = container.Resolve<AbstractPad>();
Console.WriteLine($"pad2由線程id={Thread.CurrentThread.ManagedThreadId}");
});
var result2 = act2.BeginInvoke(t =>
{
pad3 = container.Resolve<AbstractPad>();
Console.WriteLine($"pad3由線程id={Thread.CurrentThread.ManagedThreadId}");
Console.WriteLine($"object.ReferenceEquals(pad2, pad3)={object.ReferenceEquals(pad2, pad3)}");
}, null);
act1.EndInvoke(result1);
act2.EndInvoke(result2);
Console.WriteLine($"object.ReferenceEquals(pad1, pad2)={object.ReferenceEquals(pad1, pad2)}");
4.)Unity通過配置文件進行注冊
配置文件代碼:
<unity>
<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/>
<containers>
<container name="testContainer1">
<!--支持AOP-->
<extension type="Interception"/>
<register type="IOC.Interface.IPhone,IOC.Interface" mapTo="IOC.Service.ApplePhone, IOC.Service"/>
<!--是dll名稱裁良,不是命名空間-->
<!--接口多個實現(xiàn)別名獲取-->
<register type="IOC.Interface.IPhone,IOC.Interface" mapTo="IOC.Service.AndroidPhone, IOC.Service" name="Android">
<!--別名-->
<interceptor type="InterfaceInterceptor"/>
<interceptionBehavior type="Common.AOP.LogBeforeBehavior, Common"/>
<interceptionBehavior type="Common.AOP.LogAfterBehavior, Common"/>
<interceptionBehavior type="Common.AOP.ParameterCheckBehavior, Common"/>
<lifetime type="transient" />
</register>
<register type="IOC.Interface.IMicrophone, IOC.Interface" mapTo="IOC.Service.Microphone, IOC.Service"/>
<register type="IOC.Interface.IHeadphone, IOC.Interface" mapTo="IOC.Service.Headphone, IOC.Service"/>
<register type="IOC.Interface.IPower, IOC.Interface" mapTo="IOC.Service.Power, IOC.Service"/>
<register type="IOC.Interface.AbstractPad, IOC.Interface" mapTo="IOC.Service.ApplePad, IOC.Service"/>
<register type="IOC.IDAL.IBaseDAL, IOC.IDAL" mapTo="IOC.DAL.BaseDAL, IOC.DAL"/>
<register type="IOC.IBLL.IBaseBll, IOC.IBLL" mapTo="IOC.BLL.BaseBll, IOC.BLL">
<constructor>
<param name="baseDAL" type="IOC.IDAL.IBaseDAL, IOC.IDAL" />
<param name="id" type="System.Int32" value="3" />
</constructor>
</register>
<register type="IOC.IDAL.IDBContext`1, IOC.IDAL" mapTo="IOC.DAL.DBContextDAL`1, IOC.DAL"/>
</container>
</containers>
</unity>
前臺創(chuàng)建實例:
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\\Unity.Config");//找配置文件的路徑
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
IUnityContainer container = new UnityContainer();
section.Configure(container, "testContainer1");
//創(chuàng)建實例
IPhone phone = container.Resolve<IPhone>("Android");
5.)基于Unity擴展AOP:AOP面向切面編程應(yīng)用場景
在有了以上了解之后凿将,在去通過IOC容器創(chuàng)建控制器實例便清晰了
有參控制器,通過容器創(chuàng)建并構(gòu)造函數(shù)依賴注入
public class ThirdController : Controller
{
public IUserService _iUserService = null;
public ICompanyService _iCompanyService = null;
public ThirdController(IUserService userService, ICompanyService companyService)
{
_iUserService = userService;
_iCompanyService = companyService;
}
}
1.)重寫“默認控制器工廠”
public class CustomControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
//要通過容器來創(chuàng)建控制器實例 得先得到容器
//1. 獲取容器,并將后期依賴進行注冊
IUnityContainer container = DIFactory.GetContainer();
//2.通過容器創(chuàng)建控制器實例价脾,根據(jù)實例類型牧抵,查找實例構(gòu)造函數(shù)所需要的依賴項,
//通過容器內(nèi)的對象進行注入侨把,若在容器內(nèi)無法找到則無法實例該對象
return (IController)container.Resolve(t: controllerType);
}
public override IController CreateController(RequestContext requestContext, string controllerName)
{
return base.CreateController(requestContext, controllerName);
}
}
2.)替換“默認控制器工廠”
Global.asax
//用自定義的控制器工廠替換掉MVC框架中默認的控制器工廠
ControllerBuilder.Current.SetControllerFactory(new RichardControllerFactory());
經(jīng)過上述的過程犀变,