• 我记录开源系统1.6源码解析(二)上


    今天我们来解析

    wojilu.Web.Mvc.MvcFilterLoader.Init();

    这行很重要的代码,我记录已经提示说是mvc过滤器的加载器, 顾名思义,肯定和我记录的mvc模式相关。

    首先我们按VS F12快捷键转入MvcFilterLoader类,我们可以发现该类只有一个静态方法Init():

    public static void Init() {
    
                List<String> filter = MvcConfig.Instance.Filter;//获取filter : wojilu.Web.Controller.RenderHelper
    
                foreach (String t in filter) {
    
                    IMvcFilter f = ObjectContext.GetByType( t ) as IMvcFilter;
                    if (f == null) continue;
                    f.Process( MvcEventPublisher.Instance );
    
                }
    
            }
    首先定义List类型的filter变量,该变量通过MvcConfig类实例的Filter成员获得。MvcConfig是关于Mvc配置的类:
    public static readonly MvcConfig Instance = new MvcConfig();
    /// <summary>
          /// 自定义的过滤器类型,比如 wojilu.Web.Controller.RenderHelper
          /// </summary>
          public List<String> Filter { get { return _filterList; } }
    MvcConfig包含一个List<String>类型的Filter属性,返回_filterList这个私有成员,我们再来看看MvcConfig的构造函数:
    private MvcConfig() {
    
              Dictionary<String, String> dic = cfgHelper.Read( PathHelper.Map( strUtil.Join( cfgHelper.ConfigRoot, "mvc.config" ) ) );
    
              _routeConfigPath = PathHelper.Map( strUtil.Join( cfgHelper.ConfigRoot, "route.config" ) );
    
              _rootNamespace = getRootNamespace(dic);//// 多个 namespace 之间用英文逗号隔开rootNamespace: wojilu.Web.Controller
              _isParseAppId = getIsParseAppId( dic );
              _isCacheView = getIsCacheView( dic );
    
              _urlExt = getUrlExt( dic );
              _viewExt = getViewExt( dic );
              _viewDir = getViewDir( dic );
              _filterList = getFilterList( dic );
    
              dic.TryGetValue( "jsVersion", out _jsVersion );
              dic.TryGetValue( "cssVersion", out _cssVersion );
              dic.TryGetValue( "staticDomain", out _staticDomain );
              dic.TryGetValue( "noLogError", out _noLogError );
          }
    首先定义一个读取mvc.config配置文件的字典集合,我们可以先忽略其他代码直接看_filterList,它通过getFilterList这个方法来赋值:
    private List<String> getFilterList( Dictionary<String, String> dic ) {
    
               List<String> result = new List<String>();
    
               String filter;
               dic.TryGetValue( "filter", out filter );
               if (strUtil.IsNullOrEmpty( filter )) return result;
    
               String[] arrF = filter.Split( ',' );
               foreach (String f in arrF) {
                   if (strUtil.IsNullOrEmpty( f )) continue;
                   result.Add( f.Trim() );
               }
    
               return result;
           }

    可以看到关键dic.TryGetValue(“filter”,out filter)这行代码,从集合里取出关键字为filter的值,返回result.也就是说我们

    mvc.config配置文件里需包含以filter开头的键值对。

           我们再回到MvcFilterLoader的Init方法中来,获取到filter集合后,就遍历该集合

    foreach (String t in filter) {
    
                    IMvcFilter f = ObjectContext.GetByType( t ) as IMvcFilter;
                    if (f == null) continue;
                    f.Process( MvcEventPublisher.Instance );
    
                }
    这里对集合中的每一项做了处理,这里引入了IOC管理容器ObjectContext,我们直接看它的GetByType方法
    /// <summary>
            /// 从缓存中取对象(有注入的就注入,没有注入的直接生成),结果是单例
            /// </summary>
            /// <param name="typeFullName"></param>
            /// <returns></returns>
            public static Object GetByType( String typeFullName ) {
                if (Instance.TypeList.ContainsKey( typeFullName ) == false) return null;
                Type t = Instance.TypeList[typeFullName];
                return GetByType( t );
            }
    首先判断ObjectContext单例Instance中是否包含该filter,(注:以下代码过于深入,可以忽略)单例定义如下:
    /// <summary>
            /// 容器的实例(单例)
            /// </summary>
            public static ObjectContext Instance {
                get {
                    if (_instance == null) {
                        lock (syncRoot) {
                            if (_instance == null) {
                                ObjectContext ctx = new ObjectContext();
                                InitInject( ctx );
                                _instance = ctx;
                            }
                        }
                    }
                    return _instance;
                }
            }

    首先判断是否已存在_Instance,不存在就给他赋值,_instance定义如下:

    private static volatile ObjectContext _instance;

    volatile这个关键字可以参考http://msdn.microsoft.com/zh-cn/x13ttww7.aspx

    这里最重要的就是InitInject方法了

    private static void InitInject( ObjectContext ctx ) { loadAssemblyAndTypes( ctx ); resolveAndInject( ctx ); addNamedObjects( ctx ); }

    连续调用了三个函数:loadAssemblyAndTypes,resolveAndInject,addNameObjects:

    private static void loadAssemblyAndTypes( ObjectContext ctx ) {
    
               String appSettings = cfgHelper.GetAppSettings( "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 );
                   findTypesPrivate( assembly, asmName, ctx );
               }
           }
    首先从web.config中获取InjectAssemblys,然后遍历该集合,loadAssemblyPrivate函数如下
    private static Assembly loadAssemblyPrivate( String asmName, ObjectContext ctx ) {
             Assembly assembly = Assembly.Load( asmName );
             ctx.AssemblyList.Add( asmName, assembly );
             return assembly;
         }

    其实绕了这么多最终是在ObjectContext中添加AssemblyList。findTypesPrivate函数如下:

    private static void findTypesPrivate( Assembly assembly, String asmName, ObjectContext ctx ) {
               Type[] types = assembly.GetTypes();
               ctx.AssemblyTypes.Add( asmName, types );
               
               foreach (Type type in types) {
                   ctx.TypeList.Add(type.FullName, type);//这里加入InjectAssembly下的所有程序集
               }
           }

    也是对ObjectContext中的AssemblyTypes,TypeList集合添加项。

    loadAssemblyAndTypes就做这么多工作.接下来我们看resolveAndInject函数:

    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 );
    
               logger.Info( "inject Object begin..." );
               injectObjects( maps, resolvedMap );
    
               ctx.ResolvedMap = resolvedMap;
           }
    这里首先查找List<MapItem>类型的maps,用到了cdb这个类:
    /// <summary>
      /// 从内存数据库中查询数据
      /// </summary>
      /// <remarks>
      /// 数据持久化在 /framework/data/ 目录下,以json格式存储。加载之后常驻内存。
      /// 特点:直接从内存中检索,速度相当于 Hashtable。插入和更新较慢(相对而言),因为插入和更新会在内存中重建索引。
      /// </remarks>
      public class cdb 
    很清楚的可以看到此类的作用,MapItem也是比较重要的一个类
    /// <summary>
        /// 依赖注入中的配置项
        /// </summary>
        public class MapItem : CacheObject
    此类继承自CacheObject
    /// <summary>
       /// 缓存对象,常驻内存,同时以json格式存储在磁盘中
       /// </summary>
       [Serializable]
       public class CacheObject 
    这两个类留待今后的详细解析。。我们再回到cdb.findAll<MapItem>()这个方法上,看看cdb的fingAll泛型方法:
    /// <summary>
    /// 查询类型 T 的所有数据
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns>返回所有数据的列表</returns>
    public static List<T> findAll<T>() where T : CacheObject {
        IList list = MemoryDB.FindAll( typeof( T ) );
        return db.getResults<T>( list );
    }
    泛型方法再加上T类型的约束CacheObject,我们又看到了两个新类MemoryDB和db类,MemoryDB的FindAll方法如下:
    internal static IList FindAll( Type t ) {
                return new ArrayList( GetObjectsByName( t ) );
            }
    这里采用internal关键字了。。返回一个ArrayList,GetOejectsByName方法如下:
    private static IList GetObjectsByName( Type t ) {
    
                if (isCheckFileDB( t )) {
    
                    lock (chkLock) {
    
                        if (isCheckFileDB( t )) {
    
                            loadDataFromFile( t );
                            _hasCheckedFileDB[t] = true;
    
                        }
    
                    }
    
                }
                return (objectList[t.FullName] as IList);
            }
    这里调用isCheckFileDB,loadDataFromFile,不管怎样都是要返回objectList[t.FullName],看看objectList集合
    private static IDictionary objectList = Hashtable.Synchronized( new Hashtable() );

    还是个IDictionary类型..回过来再看isCheckFileDB函数:

    private static Boolean isCheckFileDB( Type t ) {
                if (_hasCheckedFileDB[t] == null) return true;
                return false;
            }
    如果_hasCheckedFileDB中不包含t,就返回true.
    private static Hashtable _hasCheckedFileDB = new Hashtable();
    再看看loadDataFromFile函数:
    private static void loadDataFromFile( Type t ) {
                if (wojilu.IO.File.Exists( getCachePath( t ) )) {
                    IList list = getListWithIndex( wojilu.IO.File.Read( getCachePath( t ) ), t );
                    objectList[t.FullName] = list;
                }
                else {
                    objectList[t.FullName] = new ArrayList();
                }
            }

    其实isCheckFileDB函数和loadDataFromFile函数都是为了返回objectList[t.FullName]..

    可以看见,我记录中的代码是一层套一层,很容易被搞晕,也可以看出作者付出了很多劳动。其实分析了这么多也就是在

    resolveAndInject函数中。。

    调用

    List<MapItem> maps = cdb.findAll<MapItem>();
               if (maps.Count <= 0) return;

    最终目的是在

    logger.Info( "resolve item begin..." );
    resolveMapItem( maps, resolvedMap, ctx );
    
    logger.Info( "inject Object begin..." );
    injectObjects( maps, resolvedMap );
    
    ctx.ResolvedMap = resolvedMap;

    这几句代码上,详细代码就不一一展开。。其实就是把系统操作记录日志,DI操作等。

    我们可以简单的归纳为ObjectContext.GetByType(String typeFullName) -->判断ObjectContext单例Instance中是否包含该filter,有就从Instance.TypeList里去取,最后就通过GetByType函数返回单例:

    /// <summary>
           /// 从缓存中取对象(有注入的就注入,没有注入的直接生成),结果是单例
           /// </summary>
           /// <param name="t"></param>
           /// <returns></returns>
           public static Object GetByType( Type t ) {
               if (t == null) return null;
               Object result = Instance.ObjectsByType[t.FullName];
    
               if (result == null) {
    
                   MapItem mapItem = getMapItemByType( t );
                   if (mapItem != null) {
                       return createInstanceAndInject( mapItem );
                   }
                   else {
                       return rft.GetInstance( t );
                   }
    
               }
               else
                   return result;
           }

    我记录的DI和Data这块今后需要深入解析下。。

    再说的简单点,MvcFilterLoader.Init()函数中的

    IMvcFilter f = ObjectContext.GetByType( t ) as IMvcFilter;
    这行就是获取
    /// <summary>
       /// MvcFilterLoader中初始化调用的
       /// </summary>
       public class RenderHelper : IMvcFilter 
    该类在wojilu.Web.Controller命名空间下。关于它的Process函数
    public void Process( MvcEventPublisher publisher ) {
    
                publisher.Begin_ProcessMvc += new EventHandler<MvcEventArgs>( publisher_Begin_ProcessMvc );
                publisher.Begin_Render += new EventHandler<MvcEventArgs>( publisher_Begin_Render );
    
            }
    我们将在下篇文章中详细解析。。
  • 相关阅读:
    scrapy爬虫系列之三--爬取图片保存到本地
    scrapy爬虫系列之四--爬取列表和详情
    python3.7.2 ssl版本过低导致pip无法使用的问题
    python3安装后无法使用退格键的问题
    位运算符和unity Layers
    unity常用小知识点
    unity -- Time类(持续更新中)
    随便说说 post-processing
    unity图片后期处理
    顶点/片元 shader 总结
  • 原文地址:https://www.cnblogs.com/johnwonder/p/2321102.html
Copyright © 2020-2023  润新知