1 IOC控制反轉和DI依賴注入
1.1 定義及作用
DIP 依賴倒置原則:系統架構時,高層模塊不應該依賴低模塊,二者通過抽象來依賴
依賴抽象而不是細節
貫徹依賴倒置原則,左邊能抽象,右邊實例化的時候不能直接用抽象,所以需要藉助第三方
高層本來是依賴低層,但是可以通過工廠(容器)來決定細節,去掉對低層的依賴。
IOC(Inversion of Control)控制反轉:把高層對低層的依賴,轉移到第三方決定,避免高層的直接依賴,那麼程序架構就具備良好的擴展性和穩定性;
DI(Dependency Injection) 依賴注入:是用來實現IOC的一種手段
在構造對象時,可以自動化的取初始化,對象需要的其他對象(構造函數注入、屬性注入、方法注入)
不管是什麼注入,都是通過反射來實現的
有了依賴注入,才能做到無限層級的依賴抽象,才能做到控制反轉
1.2 分層的意義
分層是必須的
爲什麼分層:
1、職責清晰,方便分工合作
2、代碼複用
3、體積小、方便維護
2 Unity的使用
2.1 安裝
- install-package Unity
- install-package Unity.Interception
- install-package Unity.Interception.Configuration
2.2 Unity容器初步運用
//1、聲明一個容器
IUnityContainer container = new UnityContainer();
//2、初始化容器,註冊類型
container.RegisterType<IPhone, AndroidPhone>();
//3、創建對象,通過反射實現
IPhone phone = container.Resolve<IPhone>();
phone.Call();
2.3 Unity多種註冊,一對多的註冊
//1、聲明一個容器
IUnityContainer container = new UnityContainer();
//2、初始化容器,註冊類型
container.RegisterType<IPhone, AndroidPhone>();//接口
container.RegisterType<ApplePad, ApplePadChild>();//父子類
//container.RegisterType<AbstractPad, ApplePad>();//抽象類和子類
//container.RegisterType<AbstractPad, ApplePadChild>();//會覆蓋 要想不被覆蓋 傳入形參
container.RegisterType<AbstractPad, ApplePad>("child");//抽象類和子類 一對多
container.RegisterType<AbstractPad, ApplePadChild>("GrandChild");
container.RegisterInstance<ITV>(new AppleTV(123));//註冊實例,不常用(因爲依賴細節了)
//3、創建對象,通過反射實現
IPhone phone = container.Resolve<IPhone>();
phone.Call();
//AbstractPad pad = container.Resolve<AbstractPad>();
ApplePad applePad = container.Resolve<ApplePad>();
AbstractPad childPad = container.Resolve<AbstractPad>("child");
childPad.Show();
AbstractPad GrandChildPad = container.Resolve<AbstractPad>("GrandChild");
childPad.Show();
ITV iTV = container.Resolve<ITV>();
iTV.Show();
2.4 Unity依賴注入,多層架構
////1、聲明一個容器
IUnityContainer container = new UnityContainer();
//2、初始化容器,註冊類型
container.RegisterType<IPhone, ApplePhone>();
container.RegisterType<IMicrophone, Microphone>();
container.RegisterType<IPower, Power>();
container.RegisterType<IHeadphone, Headphone>();
//3、創建對象,通過反射實現
IPhone phone = container.Resolve<IPhone>();
phone.Call();
2.5 Unity生命週期管理
//容器成了創建對象的入口,可以加入自己的管理邏輯:生命週期
//1、聲明一個容器
IUnityContainer container = new UnityContainer();
//2、初始化容器,註冊類型
//container.RegisterType<IPhone, AndroidPhone>();//默認 瞬時
//container.RegisterType<IPhone, AndroidPhone>(new TransientLifetimeManager());//瞬時 每一次都是全新生成
// container.RegisterType<IPhone, AndroidPhone>(new ContainerControlledLifetimeManager());//容器單例 單例就是不要自己實現
//3、創建對象,通過反射實現
//IPhone phone1 = container.Resolve<IPhone>();
//IPhone phone2 = container.Resolve<IPhone>();
//Console.WriteLine(object.ReferenceEquals(phone1, phone2));
//phone1.Call();
#region 線程單例
//線程單例,相同線程的實例相同,不同線程的實例不同, 如web請求/多線程操作
container.RegisterType<IPhone, AndroidPhone>(new PerThreadLifetimeManager());//線程單例 同一個線程就是單例的 不同線程就是不同的
IPhone phone1 = null;
Action action1 = new Action(() =>
{
phone1 = container.Resolve<IPhone>();
Console.WriteLine($"iphone1由線程ID={Thread.CurrentThread.ManagedThreadId}");
});
var result1 = action1.BeginInvoke(null, null);
IPhone phone2 = null;
Action action2 = new Action(() =>
{
phone2 = container.Resolve<IPhone>();
Console.WriteLine($"iphone2由線程ID={Thread.CurrentThread.ManagedThreadId}");
});
IPhone phone3 = null;
var result2 = action2.BeginInvoke(t =>
{
phone3 = container.Resolve<IPhone>();
Console.WriteLine($"iphone3由線程ID={Thread.CurrentThread.ManagedThreadId}");
Console.WriteLine($"object.ReferenceEquals(phone2, phone3) = {object.ReferenceEquals(phone2, phone3)}");
}, null);
action1.EndInvoke(result1);
action2.EndInvoke(result2);
Console.WriteLine($"object.ReferenceEquals(phone1, phone2) = {object.ReferenceEquals(phone1, phone2)}");
#endregion
//container.RegisterType<IPhone, AndroidPhone>(new HierarchicalLifetimeManager());//分級容器單例
//IUnityContainer unityContainer = container.CreateChildContainer();//獲取子容器
//container.RegisterType<IPhone, AndroidPhone>(new ExternallyControlledLifetimeManager());//外部可釋放單例
//container.RegisterType<IPhone, AndroidPhone>(new PerResolveLifetimeManager());//循環引用 不推薦
3 AOP面向切面編程
<!--<?xml version="1.0" encoding="utf-8" ?>-->
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
</configSections>
<unity>
<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/>
<containers>
<container name="testContainer">
<extension type="Interception"/>
<register type="面向切面編程.UnityWay.IUserProcessor,面向切面編程" mapTo="面向切面編程.UnityWay.UserProcessor, 面向切面編程">
<interceptor type="InterfaceInterceptor"/>
<interceptionBehavior type="面向切面編程.UnityWay.ExceptionLoggingBehavior,面向切面編程"/>
<interceptionBehavior type="面向切面編程.UnityWay.CachingBehavior,面向切面編程"/>
<interceptionBehavior type="面向切面編程.UnityWay.LogBeforeBehavior,面向切面編程"/>
<interceptionBehavior type="面向切面編程.UnityWay.ParameterCheckBehavior,面向切面編程"/>
<interceptionBehavior type="面向切面編程.UnityWay.LogAfterBehavior,面向切面編程"/>
</register>
</container>
</containers>
</unity>
</configuration>
public class ParameterCheckBehavior : IInterceptionBehavior
{
public bool WillExecute
{
get
{
//throw new NotImplementedException();
return true;
}
}
public IEnumerable<Type> GetRequiredInterfaces()
{
//throw new NotImplementedException();
return Type.EmptyTypes;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
//throw new NotImplementedException();
Console.WriteLine("ParameterCheckBehavior");
User user = input.Inputs[0] as User;//可以不寫死,反射+特性完成對數據的有效性檢測
if (user.Pwd.Length<5)
{
//返回一個異常
return input.CreateExceptionMethodReturn(new Exception("密碼長度不能小於10"));
}
else
{
return getNext().Invoke(input, getNext);
}
}
}
public class CachingBehavior : IInterceptionBehavior
{
private static Dictionary<string, object> CachingDictionary = new Dictionary<string, object>();
public bool WillExecute
{
get
{
//throw new NotImplementedException();
return true;
}
}
public IEnumerable<Type> GetRequiredInterfaces()
{
//throw new NotImplementedException();
return Type.EmptyTypes;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
//throw new NotImplementedException();
Console.WriteLine("CachingBehavior");
string key = $"{input.MethodBase.Name}_{Newtonsoft.Json.JsonConvert.SerializeObject(input.Inputs)}";
if (CachingDictionary.ContainsKey(key))
{
return input.CreateMethodReturn(CachingDictionary[key]);//相當於短路器 ,直接返回
}
else
{
IMethodReturn methodReturn = getNext().Invoke(input, getNext);
if (methodReturn.ReturnValue!=null)
{
CachingDictionary.Add(key, methodReturn.ReturnValue);
}
return methodReturn;
}
}
}
public class ExceptionLoggingBehavior : IInterceptionBehavior
{
public bool WillExecute
{
get
{
//throw new NotImplementedException();
return true;
}
}
public IEnumerable<Type> GetRequiredInterfaces()
{
//throw new NotImplementedException();
return Type.EmptyTypes;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
//throw new NotImplementedException();
IMethodReturn methodReturn = getNext().Invoke(input, getNext);
Console.WriteLine("ExceptionLoggingBehavior");
if (methodReturn.Exception==null)
{
Console.WriteLine("無異常");
}
else
{
Console.WriteLine($"異常:{methodReturn.Exception.Message}");
}
return methodReturn;
}
}
public class LogAfterBehavior : IInterceptionBehavior
{
public bool WillExecute
{
get
{
return true;
//throw new NotImplementedException();
}
}
public IEnumerable<Type> GetRequiredInterfaces()
{
//throw new NotImplementedException();
return Type.EmptyTypes;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
//throw new NotImplementedException();
IMethodReturn methodReturn = getNext().Invoke(input, getNext);
Console.WriteLine("LogAfterBehavior");
Console.WriteLine(input.MethodBase.Name);//獲取方法名稱
foreach (var item in input.Inputs)
{
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(item));
}
Console.WriteLine($"返回值:{methodReturn.ReturnValue}");
return methodReturn;
}
}
public class LogBeforeBehavior : IInterceptionBehavior
{
public bool WillExecute
{
get
{
return true;
//throw new NotImplementedException();
}
}
public IEnumerable<Type> GetRequiredInterfaces()
{
// throw new NotImplementedException();
return Type.EmptyTypes;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
// throw new NotImplementedException();
Console.WriteLine("LogBeforeBehavior");
//input拿到所有參數信息
foreach (var item in input.Inputs)
{
//反射或者序列化顯示更多信息//install-package Newtonsoft.Json
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(item));//install-package Newtonsoft.Json
}
//
return getNext()(input, getNext);//getNext()得到委託實例;
}
}
public class UnityConfigAOP
{
public static void Show()
{
User user = new User() { Name = "Admin", Pwd = "123" };
{
//通過反射創建對象
IUnityContainer container = new UnityContainer();
container.RegisterType<IUserProcessor, UserProcessor>();
IUserProcessor processor = container.Resolve<IUserProcessor>();
processor.RegUser(user);
}
{
IUnityContainer container = new UnityContainer();
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CfgFiles\\Unity.config");
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
UnityConfigurationSection unityConfigurationSection = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
unityConfigurationSection.Configure(container, "testContainer");
IUserProcessor processor = container.Resolve<IUserProcessor>();
processor.RegUser(user);
}
}
}
public interface IUserProcessor
{
void RegUser(User user);
}
public class UserProcessor : IUserProcessor
{
public void RegUser(User user)
{
Console.WriteLine($"用戶已註冊,用戶名稱={user.Name} Password={user.Pwd}");
}
}
public class User
{
public string Name { get; set; }
public string Pwd { get; set; }
}