这篇为了进一步加深对我记录IOC管理容器的运行流程,我们继续分析ObjectContext这个类。主要是对InitInJect这个方
法继续分析。
private static void InitInject( ObjectContext ctx ) { loadAssemblyAndTypes( ctx ); resolveAndInject( ctx ); addNamedObjects( ctx ); }
ObjectContext类位于wojilu项目的DI文件夹中,如图:
可以看到DI文件夹里包含MapItem和ObjectContext两个类。说明这两个类跟DI紧密关联。
第一行调用loadAssemblyAndTypes方法:
private static void loadAssemblyAndTypes( ObjectContext ctx ) { String appSettings = cfgHelper.GetAppSettings( "InjectAssembly" );//读取web.config里的key为InjectAssembly的配置项 if (strUtil.IsNullOrEmpty( appSettings )) return; String[] strArray = appSettings.Split( new char[] { ',' } ); foreach (String asmStr in strArray) {//遍历所有以","分割的程序集 if (strUtil.IsNullOrEmpty( asmStr )) continue; String asmName = asmStr.Trim(); Assembly assembly = loadAssemblyPrivate(asmName, ctx);//加载web.config中的InjectAssembly,并加入ObjectContext findTypesPrivate( assembly, asmName, ctx ); } }我们看看loadAssemblyPrivate这个方法:
/// <summary> /// 根据程序集名称加载web.config中的InjectAssembly,并加入ObjectContext /// </summary> /// <param name="asmName">程序集名称</param> /// <param name="ctx">容器实例</param> /// <returns>返回程序集</returns> private static Assembly loadAssemblyPrivate( String asmName, ObjectContext ctx ) { Assembly assembly = Assembly.Load( asmName );//根据程序集名称加载程序集 ctx.AssemblyList.Add( asmName, assembly );//加入ObjectContext的AssemblyList(所有纳入容器管理的程序集) return assembly;//返回程序集 }接下来findTypesPrivate方法:
private static void findTypesPrivate( Assembly assembly, String asmName, ObjectContext ctx ) { Type[] types = assembly.GetTypes();//返回程序集里定义的类型 ctx.AssemblyTypes.Add(asmName, types);//这里加入ObjectContext的AssemblyTypes属性,所有程序集名称,所有类型 foreach (Type type in types) {//遍历程序集下的所有类型 ctx.TypeList.Add(type.FullName, type);//这里加入InjectAssembly下的TypeList所有类型,所有纳入容器管理的类型 } }loadAssemblyAndTypes方法还是没什么很多的内容的,我们看看第二行的resolveAndInject( ctx ):
private static void resolveAndInject( ObjectContext ctx ) { List<MapItem> maps = cdb.findAll<MapItem>();//查询所有依赖注入里的配置项 if (maps.Count <= 0) return; Dictionary<String, MapItem> resolvedMap = new Dictionary<String, MapItem>(); logger.Info( "resolve item begin..." );//记录日志 resolveMapItem( maps, resolvedMap, ctx );//处理所有MapItem logger.Info( "inject Object begin..." ); injectObjects( maps, resolvedMap );//resolvedMap,处理过的MapItem:wojilu.Web.Context.ContextInit ctx.ResolvedMap = resolvedMap; }
List<MapItem> maps = cdb.findAll<MapItem>();展开后涉及到比较多的代码,我们来把部分代码展开:
/// <summary> /// 查询类型 T 的所有数据 /// </summary> /// <typeparam name="T"></typeparam> /// <returns>返回所有数据的列表</returns> public static List<T> findAll<T>() where T : CacheObject { IList list = MemoryDB.FindAll( typeof( T ) );//如wojilu.DI.MapItem return db.getResults<T>( list ); }
这个方法在cdb类里:
/// <summary> /// 从内存数据库中查询数据 /// </summary> /// <remarks> /// 数据持久化在 /framework/data/ 目录下,以json格式存储。加载之后常驻内存。 /// 特点:直接从内存中检索,速度相当于 Hashtable。插入和更新较慢(相对而言),因为插入和更新会在内存中重建索引。 /// </remarks> public class cdbcdb.findAll<T>()方法又会调用MemoryDB.FindAll(typeof(T)):
internal static IList FindAll( Type t ) { return new ArrayList( GetObjectsByName( t ) ); }GetObjectsByName(Type t)如下:
/// <summary> /// 根据类型t得到以该类型t命名的配置文件中的所有类型 /// </summary> /// <param name="t"></param> /// <returns></returns> private static IList GetObjectsByName( Type t ) { if (isCheckFileDB( t )) {//是否应该检查配置文件 lock (chkLock) { if (isCheckFileDB( t )) { loadDataFromFile( t );//从配置文件加载类型t _hasCheckedFileDB[t] = true; } } } return (objectList[t.FullName] as IList); }loadDataFromFile(Type t )方法如下:
/// <summary> /// 从配置文件中加载所有类型 /// </summary> /// <param name="t"></param> private static void loadDataFromFile( Type t ) { if (wojilu.IO.File.Exists( getCachePath( t ) )) {//检查以类型t命名的配置文件是否存在 IList list = getListWithIndex( wojilu.IO.File.Read( getCachePath( t ) ), t ); objectList[t.FullName] = list; } else { objectList[t.FullName] = new ArrayList(); } }
最主要是getListWithIndex( String jsonString, Type t )方法:
private static IList getListWithIndex( String jsonString, Type t ) { IList list = new ArrayList(); if (strUtil.IsNullOrEmpty( jsonString )) return list; List<object> lists = JsonParser.Parse( jsonString ) as List<object>;//解析json格式的数组,返回Dictionary类型的数组,包含Name,Type foreach (Dictionary<String, object> map in lists) {//遍历 CacheObject obj = JSON.setValueToObject( t, map ) as CacheObject;//把json数组里的Type转换为t对象里的属性 int index = list.Add( obj ); addIdIndex( t.FullName, obj.Id, index ); makeIndexByInsert( obj ); } return list; }
至于resolveMapItem和injectObjects
private static void resolveMapItem( List<MapItem> maps, Dictionary<String, MapItem> resolvedMap, ObjectContext ctx )
private static void injectObjects( List<MapItem> mapItems, Dictionary<String, MapItem> resolvedMap )
两个方法也是跟注入对象相关。我们最后来看下addNamedObjects方法:
private static void addNamedObjects( ObjectContext ctx ) { Dictionary<String, MapItem> resolvedMap = ctx.ResolvedMap; Hashtable namedObjects = new Hashtable(); foreach (KeyValuePair<String, MapItem> entry in resolvedMap) { MapItem item = entry.Value; namedObjects.Add( item.Name, item.TargetObject ); } ctx.ObjectsByName = namedObjects; }
这个很简单,把处理过的MapItem附给根据名称罗列的对象表(HashTable)。
总结:今后还得继续对wojilu的DI容器代码分析深入研究。