MVC 框架中的缓存

     在程序中加入缓存的目的很多是为了提高程序的性能,提高数据的查找效率,在MVC框架中也引入了非常多的缓存,比如Controller的匹配查找,Controller,ControllerDescriptorCache...大部分的缓存设计都是采用了key-value的结构;

ControllerTypeCache

     ControllerTypeCache类是对应用程序集中的Controller类型进行缓存,当请求进入MVC框架中,需要根据RouteData中ControllerName 以及命名空间来进行查找出正确的Controller类型。如果程序比较大时,Controller就要对程序中所有的dll中的类进行查找匹配,效率肯定非常低下;

     在MVC框架中对于Controller类的查找匹配引入了ControllerTypeCache类,在缓存类中存在Dictionary<string, ILookup<string, Type>>的缓存结构,在这个结构中key为去掉Controller后缀的Controller类型的Name,Value 值为ILookup<string, Type>结构,其中key值为命名空间名称,Value 为Controller的类型;而且这些key都是忽略大小写;

     

     public void EnsureInitialized(IBuildManager buildManager)
     {
         if (_cache == null)
         {
            lock (_lockObj)
            {
                if (_cache == null)
                 {
                     List<Type> controllerTypes = TypeCacheUtil.GetFilteredTypesFromAssemblies(TypeCacheName, IsControllerType, buildManager);
                     var groupedByName = controllerTypes.GroupBy(
                                          t => t.Name.Substring(0, t.Name.Length - "Controller".Length), StringComparer.OrdinalIgnoreCase);
                        _cache = groupedByName.ToDictionary(
                                               g => g.Key,
                                               g => g.ToLookup(t => t.Namespace ?? String.Empty, StringComparer.OrdinalIgnoreCase),
                                               StringComparer.OrdinalIgnoreCase);
                    }
                }
            }
        }

         ControllerTypeCache类中EnsureInitialized方法就是构建缓存结构,GetFilteredTypesFromAssemblies方法时获取到应用程序集中所有的Control类型,在MVC框架中会在应用程序启动时加载所有的dll类中的Controller类型然后调用IBuildManager接口的方法CreateCachedFile方法将这些类型序列到磁盘文件中,下次请求到来时直接从磁盘文件中加载,文件名字为“MVC-ControllerTypeCache.xml”;_cache 缓存文件的地址是在HttpRuntime.CodegenDir+"//UserCache//MVC-ControllerTypeCache.xml";

ReaderWriterCache<TKey, TValue>
        ReaderWriterCache是一个读写缓存抽象类,它的缓存结构也是key-value的形式,在MVC框架中ControllerDescriptorCache类,ActionMethodDispatcherCache类都继承了这个抽象类;在ControllerDescriptorCache类中key为Controller的Type类型,Value为ControllerDescriptor类; ActionMethodDispatcherCache类中key为action方法的MethodInfo,Value为ActionMethodDispatcher类;

      在ReaderWriterCache类中有个重要的读取或是设置缓存的FetchOrCreateItem的方法;

 private readonly ReaderWriterLockSlim _readerWriterLock = new ReaderWriterLockSlim();
 protected TValue FetchOrCreateItem<TArgument>(TKey key, Func<TArgument, TValue> creator, TArgument state)
 {
   // first, see if the item already exists in the cache
    _readerWriterLock.EnterReadLock();
    try
    {
      TValue existingEntry;
      if (_cache.TryGetValue(key, out existingEntry))
        {
           return existingEntry;
        }
     }
     finally
     {
          _readerWriterLock.ExitReadLock();
     }

     // insert the new item into the cache
     TValue newEntry = creator(state);
     _readerWriterLock.EnterWriteLock();
     try
     {
        TValue existingEntry;
        if (_cache.TryGetValue(key, out existingEntry))
        {
           // another thread already inserted an item, so use that one
           return existingEntry;
         }
         _cache[key] = newEntry;
          return newEntry;
      }
      finally
      {
         _readerWriterLock.ExitWriteLock();
      }
    }

      在FetchOrCreateItem方法中引入了ReaderWriterLockSlim类,这个类的目的是用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问,当根据key获取vlaue值时,读取缓存时根据EnterReadLock方法加入读锁,当读取完毕后,通过ExitReadLock方法释放读锁;如果缓存没有命中,则通过调用创建类型的委托创建value并写入到缓存中,在写入缓存的之前会再次从缓存中读取,如果没有则写入,防止并发造成的重复写入;

  

     protected override ControllerDescriptor GetControllerDescriptor(ControllerContext controllerContext)
     {
         // Frequently called, so ensure delegate is static
         Type controllerType = controllerContext.Controller.GetType();
         ControllerDescriptor controllerDescriptor = DescriptorCache.GetDescriptor(
                 controllerType: controllerType,
                 creator: ReflectedAsyncControllerDescriptor.DefaultDescriptorFactory,
                 state: controllerType);
            return controllerDescriptor;
      }

 ReflectedAttributeCache

      ReflectedAttributeCache类时缓存作用于action方法中的一些特性的列表缓存,从这个缓存中可以很快获取到对于的方法的一些特性信息,在这个缓存类的类结构也是采用的key-value的形式;

     

      private static readonly ConcurrentDictionary<MethodInfo, ReadOnlyCollection<ActionMethodSelectorAttribute>> _actionMethodSelectorAttributeCache = new ConcurrentDictionary<MethodInfo, ReadOnlyCollection<ActionMethodSelectorAttribute>>();
        private static readonly ConcurrentDictionary<MethodInfo, ReadOnlyCollection<ActionNameSelectorAttribute>> _actionNameSelectorAttributeCache = new ConcurrentDictionary<MethodInfo, ReadOnlyCollection<ActionNameSelectorAttribute>>();
        private static readonly ConcurrentDictionary<MethodInfo, ReadOnlyCollection<FilterAttribute>> _methodFilterAttributeCache = new ConcurrentDictionary<MethodInfo, ReadOnlyCollection<FilterAttribute>>();

        private static readonly ConcurrentDictionary<Type, ReadOnlyCollection<FilterAttribute>> _typeFilterAttributeCache = new ConcurrentDictionary<Type, ReadOnlyCollection<FilterAttribute>>();

  在ReflectedAttributeCache类中存在了4种缓存,缓存的格式都是ConcurrentDictionary类型,

    _actionMethodSelectorAttributeCache 缓存:key 为action方法的MethodInfo,value为继承了ActionMethodSelectorAttribute抽象类的一些子类(HttpPostAttribute,HttpGetAttribute)的只读集合;ActionMethodSelectorAttribute类的目的是筛选请求的方式;

    _actionNameSelectorAttributeCache 缓存:key 为action方法的MethodInfo,value为继承了ActionNameSelectorAttribute抽象类的一些子类(ActionNameAttribute)的只读集合;ActionMethodSelectorAttribute类的目的是筛选请求方法的名字;

     _methodFilterAttributeCache 缓存:key 为action方法的MethodInfo,value为继承了FilterAttribute抽象类的一些子类的只读集合;FilterAttribute类的目的是action的过滤器特性;

    _typeFilterAttributeCache 缓存:key 为Controller类的Type,value为继承了FilterAttribute抽象类的一些子类的只读集合;FilterAttribute类的目的是Controller的过滤器特性;

 在ReflectedAttributeCache类中获取特性集合都是通过GetAttributes方法

  private static ReadOnlyCollection<TAttribute> GetAttributes<TMemberInfo, TAttribute>(ConcurrentDictionary<TMemberInfo, ReadOnlyCollection<TAttribute>> lookup, TMemberInfo memberInfo)
            where TAttribute : Attribute
            where TMemberInfo : MemberInfo
  {
        // Frequently called, so use a static delegate
        // An inline delegate cannot be used because the C# compiler does not cache inline delegates that reference generic method arguments
        return lookup.GetOrAdd( memberInfo,
                               CachedDelegates<TMemberInfo, TAttribute>.GetCustomAttributes);
   }

  private static class CachedDelegates<TMemberInfo, TAttribute>
            where TAttribute : Attribute
            where TMemberInfo : MemberInfo
  {
        internal static Func<TMemberInfo, ReadOnlyCollection<TAttribute>> GetCustomAttributes = (TMemberInfo memberInfo) =>
         {
                return new ReadOnlyCollection<TAttribute>((TAttribute[])memberInfo.GetCustomAttributes(typeof(TAttribute), inherit: true));
         };
  }

 



 
posted @ 2015-12-16 16:14  飞蛾扑火  阅读(895)  评论(0编辑  收藏  举报