今天來介紹配置文件的定義和加載,先給出配置文件的內容,然後在詳細介紹裡面各節的含義,以及如何用程序加載配置文件,內容如下:
配置文件
<?xml version="1.0" encoding="utf-8" ?>
<AOP>
<Regeisty>
<IPreProcess>
<Aspect id="AddPreProcessLog" value="YQL.TestProject:YQL.TestProject.AddPreProcessLog" isDefault="true"/>
<Aspect id="VerifyPermission" value="YQL.AOP:YQL.AOP.VerifyPermission"/>
</IPreProcess>
<IPostProcess>
<Aspect id="AddPostProcessLog" value="YQL.TestProject:YQL.TestProject.AddPostProcessLog" isDefault="true"/>
</IPostProcess>
<IExceptionHandler>
<Aspect id="SimplyExceptionHandler" value="YQL.TestProject:YQL.TestProject.SimplyExceptionHandler" isDefault="true"/>
</IExceptionHandler>
</Regeisty>
<Application>
<Class id="YQL.TestProject:YQL.TestProject.Test">
<Method id="Int32 Test4(System.String)">
<IPreProcess>
<Aspect id="AddPreProcessLog"/>
</IPreProcess>
<IPostProcess>
<Aspect id="AddPostProcessLog"/>
<Aspect id="TestException"/>
</IPostProcess>
<IExceptionHandler>
<Aspect id="SimplyExceptionHandler"/>
</IExceptionHandler>
</Method>
</Class>
</Application>
</AOP>
配置文件中包含兩個部分分別是Regeisty節和Application節,Regeisty節包含了所有切面的實現類的定義,包含id,value和isDefault三個屬性:id表示這個實現的代號,在Application節可以通過這個代號來引用某個實現類,作為主鍵標識,必須唯一;value是這個實現類的具體信息,由所在的程序集和類的全名組成,中間用冒號分隔;isDefault屬性為可選,如果設置為true,則表示某個方法在沒有特殊的定義的情況下,使用這個實現類來實現某個具體的切面處理。Application節包含了所有需要特殊處理的方法的信息,首先是這個方法的所在類(類的信息描述與前面相同),然後是方法名,包括返回值類型和參數類型。按照我的設想,這個配置文件應該是通過一個配置工具,通過反射和用戶的一些選擇操作來生成的,當然現在這個配置工具還不存在,留待以後擴展。
接下來是配置文件的加載,我們定義了一個AopConfigManager類用來實現配置文件的加載以及維護,這裡面包含了兩個對外的方法分別用來初始化配置文件,和為方法植入時提供需要植入的切面信息,這兩個方法的實現如下:
Init
/// <summary>
/// 初始化配置文件信息
/// </summary>
/// <param name="configFilePath">配置文件路徑</param>
public static void Init(string configFilePath)
{
XPathDocument document = new XPathDocument(configFilePath);
XPathNavigator rootNavigator = document.CreateNavigator();
//初始化各個方面的配置信息
InitAspectInfo(rootNavigator);
//初始化非默認行為的方法的方面配置信息
InitClassInfo(rootNavigator);
}
這裡通過XPathNavigator來實現xml文件的讀取,然後分別初始化Regeisty節和Application節的內容,XPathNavigator類專門用來進行xml文件xpath形式的讀取,具體的使用可以參見msdn中的內容,我就不多說了 XPathNavigator 。
GetMethodAspectInfo
/// <summary>
/// 獲取指定方法的指定方面的信息
/// </summary>
/// <param name="methodInfo">方法的信息</param>
/// <param name="aspectType">指定的方面</param>
/// <returns></returns>
public static List<Type> GetMethodAspectInfo(MethodInfo methodInfo, AspectTypes aspectType)
{
string methodName = methodInfo.ToString();
string typeName = ReflectionHelper.GetTypeUniqueName(methodInfo.DeclaringType);
List<Type> typeList = null;
List<string> typeNameList = null;
List<string> typeValueList = new List<string>();
//讀獲取該方法的方面信息
if (_classInfoDict.ContainsKey(typeName))
{
ClassTag classTag = _classInfoDict[typeName];
typeNameList = classTag.GetAspectInfoList(methodName, aspectType);
}
string aspectName = EnumHelper.GetEnumDesceiption(aspectType);
AspectTag aspectTag = _aspectInfoDict[aspectName];
//沒有在配置文件中指定,則使用默認的配置
if (null == typeNameList || 0 == typeNameList.Count)
{
typeNameList = aspectTag.GetDefaultAspectList();
}
foreach (string str in typeNameList)
{
typeValueList.Add(aspectTag.GetAspectTypeUniqueName(str));
}
typeList = ConvertToTypeList(typeValueList);
return typeList;
}
該方法根據傳入的方法信息以及切面的枚舉項,從已經加載的配置文件中進行查找,如果找不到,則對起使用默認的配置,然後在將文本形式的類的信息通過反射轉換成Type類型。
類的實現細節主要是一些xml文件的操作,這裡就不貼出全部代碼了,如果有需要,我會在本系列結束後提供完整的源碼下載。另外從之前幾篇文章的回復當中看出,有些園友可能對我這個框架的期待過高了,其實這只是一個非常簡單的AOP框架,主要就是為了實踐一下之前所學習的Emit中的一些內容,然後實現了一個AOP框架所需要具有的幾個最基本的功能,甚至可能還稱不上是一個完整AOP框架,大家不要期待太多,不然真要把我慚愧死了!