代码改变世界

我记录开源系统1.6源码解析(二)之IOC容器浅析

2012-01-16 21:56  爱研究源码的javaer  阅读(286)  评论(0编辑  收藏  举报

这篇为了进一步加深对我记录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 cdb
cdb.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容器代码分析深入研究。