MVC5 Controller简要创建过程(2):由ControllerFactory创建Controller

上文已经完成了ControllerFactory的创建,接下来就是调用其CreateController()方法创建Controller了。

DefaultControllerFactory中CreateController()的实现:

        public virtual IController CreateController(RequestContext requestContext, string controllerName)
        {
            //...
            Type controllerType = GetControllerType(requestContext, controllerName);
            IController controller = GetControllerInstance(requestContext, controllerType);
            return controller;
        }

很明显,首先根据controllerName获得controller类型,再根据controller类型获得controller实例。

先看GetControllerType()方法:

 protected internal virtual Type GetControllerType(RequestContext requestContext, string controllerName)
        {
            RouteData routeData = requestContext.RouteData;
            if (routeData != null && routeData.HasDirectRouteMatch())
            {
                return GetControllerTypeFromDirectRoute(routeData);
            }

            // first search in the current route‘s namespace collection
            object routeNamespacesObj;
            Type match;
            if (routeData.DataTokens.TryGetValue(RouteDataTokenKeys.Namespaces, out routeNamespacesObj))
            {
                IEnumerable<string> routeNamespaces = routeNamespacesObj as IEnumerable<string>;
                if (routeNamespaces != null && routeNamespaces.Any())
                {
                    HashSet<string> namespaceHash = new HashSet<string>(routeNamespaces, StringComparer.OrdinalIgnoreCase);
                    match = GetControllerTypeWithinNamespaces(routeData.Route, controllerName, namespaceHash);

                    // the UseNamespaceFallback key might not exist, in which case its value is implicitly "true"
                    if (match != null || false.Equals(routeData.DataTokens[RouteDataTokenKeys.UseNamespaceFallback]))
                    {
                        // got a match or the route requested we stop looking
                        return match;
                    }
                }
            }

            // then search in the application‘s default namespace collection
            if (ControllerBuilder.DefaultNamespaces.Count > 0)
            {
                HashSet<string> namespaceDefaults = new HashSet<string>(ControllerBuilder.DefaultNamespaces, StringComparer.OrdinalIgnoreCase);
                match = GetControllerTypeWithinNamespaces(routeData.Route, controllerName, namespaceDefaults);
                if (match != null)
                {
                    return match;
                }
            }

            // if all else fails, search every namespace
            return GetControllerTypeWithinNamespaces(routeData.Route, controllerName, null /* namespaces */);
        }

关于DirectRouteMatch先留个坑,以后填。

首先根据当前路由的命名空间查找controller,如果查找失败,则查找当前ControllerBuilder的默认命名空间,最后查找每个命名空间。我们注意到这三个步骤都调用了GetControllerTypeWithinNamespaces()方法,那么它具体怎么实现呢?

以下既是GetControllerTypeWithinNamespaces()的具体实现:

private Type GetControllerTypeWithinNamespaces(RouteBase route, string controllerName, HashSet<string> namespaces)
        {
            // Once the master list of controllers has been created we can quickly index into it
            ControllerTypeCache.EnsureInitialized(BuildManager);

            ICollection<Type> matchingTypes = ControllerTypeCache.GetControllerTypes(controllerName, namespaces);
            switch (matchingTypes.Count)
            {
                case 0:
                    // no matching types
                    return null;

                case 1:
                    // single matching type
                    return matchingTypes.First();

                default:
                    // multiple matching types
                    throw CreateAmbiguousControllerException(route, controllerName, matchingTypes);
            }
        }

看来具体的查找又和一个ControllerTypeCache类型的对象有关,并且只在找到唯一controller类型时将它返回。

那么来看看ControllerTypeCache类型吧:

internal sealed class ControllerTypeCache
    {
        private volatile Dictionary<string, ILookup<string, Type>> _cache;
        private object _lockObj = new object();
        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);
                    }
                }
            }
        }

        public ICollection<Type> GetControllerTypes(string controllerName, HashSet<string> namespaces)
        {
            HashSet<Type> matchingTypes = new HashSet<Type>();

            ILookup<string, Type> namespaceLookup;
            if (_cache.TryGetValue(controllerName, out namespaceLookup))
            {
                // this friendly name was located in the cache, now cycle through namespaces
                if (namespaces != null)
                {
                    foreach (string requestedNamespace in namespaces)
                    {
                        foreach (var targetNamespaceGrouping in namespaceLookup)
                        {
                            if (IsNamespaceMatch(requestedNamespace, targetNamespaceGrouping.Key))
                            {
                                matchingTypes.UnionWith(targetNamespaceGrouping);
                            }
                        }
                    }
                }
                else
                {
                    // if the namespaces parameter is null, search *every* namespace
                    foreach (var namespaceGroup in namespaceLookup)
                    {
                        matchingTypes.UnionWith(namespaceGroup);
                    }
                }
            }

            return matchingTypes;
        }
        //...
)

原来 EnsureInitialized()用来确保_cache被初始化,而_cache则是根据 buildManager.GetReferencedAssemblies()得到的所有引用的程序集,将程序集中所有controller取出并将contoller.Name去掉controller后缀作为键的字典类型,字典的值又是一个以controller所在Namespace为键,controller实际类型为值的Lookup类型。

接下来的GetControllerTypes()就很明显了,就是根据传来的controllerName和namespaces参数查找controller类型并返回。

至此我们便了解了获得controller类型的整个流程,接下来便是controller实例的创建了。

GetControllerInstance()的实现很简单:

protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            return ControllerActivator.Create(requestContext, controllerType);
        }

真正的实现还是在IControllerActivator类型实例的Create()方法中,先看下这个实例如何生成:

         private IResolver<IControllerActivator> _activatorResolver;
         private IControllerActivator _controllerActivator;
         internal DefaultControllerFactory(IControllerActivator controllerActivator, IResolver<IControllerActivator> activatorResolver, IDependencyResolver dependencyResolver)
        {
            if (controllerActivator != null)
            {
                _controllerActivator = controllerActivator;
            }
            else
            {
                _activatorResolver = activatorResolver ?? new SingleServiceResolver<IControllerActivator>(
                                                              () => null,
                                                              new DefaultControllerActivator(dependencyResolver),
                                                              "DefaultControllerFactory constructor");
            }
        }

        private IControllerActivator ControllerActivator
        {
            get
            {
                if (_controllerActivator != null)
                {
                    return _controllerActivator;
                }
                _controllerActivator = _activatorResolver.Current;
                return _controllerActivator;
            }
        }

这我们就很熟悉了--和之前ControllerFactory是一样的。

最后看一下默认ControllerActivator--DefaultControllerActivator的实现:

 private class DefaultControllerActivator : IControllerActivator
        {
            private Func<IDependencyResolver> _resolverThunk;
            public DefaultControllerActivator(IDependencyResolver resolver)
            {
                if (resolver == null)
                {
                    _resolverThunk = () => DependencyResolver.Current;
                }
                else
                {
                    _resolverThunk = () => resolver;
                }
            }

            public IController Create(RequestContext requestContext, Type controllerType)
            {return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
            }
        }

没什么复杂的,也和之前创建ControllerFactory一样,默认实现为DefaultDependencyResolver中的GetService()方法:利用反射创建一个Controller。

public object GetService(Type serviceType)
            {
                // Since attempting to create an instance of an interface or an abstract type results in an exception, immediately return null
                // to improve performance and the debugging experience with first-chance exceptions enabled.
                if (serviceType.IsInterface || serviceType.IsAbstract)
                {
                    return null;
                }

                try
                {
                    return Activator.CreateInstance(serviceType);
                }
                catch
                {
                    return null;
                }
            }

至此,我们终于了解了一个Controller的全过程。

时间: 2024-10-12 16:59:51

MVC5 Controller简要创建过程(2):由ControllerFactory创建Controller的相关文章

Spring源码解析 – AnnotationConfigApplicationContext容器创建过程

Spring在BeanFactory基础上提供了一些列具体容器的实现,其中AnnotationConfigApplicationContext是一个用来管理注解bean的容器,从AnnotationConfigApplicationContext的实现结构图中可以看出: AnnotationConfigApplicationContext继承GenericApplicationContext这个通用应用上下文,GenericApplicationContext内部定义了一个DefaultList

Python之变量的创建过程

Python之变量的创建过程 一.变量创建过程 首先,当我们定义了一个变量name = 'Kwan'的时候,在内存中其实是做了这样一件事: 程序开辟了一块内存空间,将'Kwan'存储进去,再让变量名name指向'Kwan'所在的内存地址.如下图所示: 我们可以通过id()方法查看这个变量在内存中的地址. name = 'Kwan' print(id(name)) 二.变量的修改 一般我们认为修改一个变量就是用新值把就旧值覆盖掉,可Python真是这么实现的么? name = 'Kwan' pri

Java 对象的创建过程

类的初始化与实例化一个 Java 对象的创建过程往往包括类的初始化 和 实例化 两个阶段.Java 规范规定一个对象在可以被使用之前必须要被正确地初始化.在类初始化过程中或初始化完毕后,根据具体情况才会去对类进行实例化.在实例化一个对象时,JVM 首先会检查相关类型是否已经加载并初始化,如果没有,则 JVM 立即进行加载并调用类构造器完成类的初始化.Java 对象的创建方式一个对象在可以被使用之前必须要被正确地实例化.在 Java 程序中,有多种方法可以创建对象,最直接的一种就是使用 new 关

MVC5 Controller简要创建过程

即将离职,闲来无事回顾下MVC的源码,到了Controller创建这里,由于流程有点复杂,鉴于自己记性不太好,索性就记录一下吧,方便日后参照. 首先看MvcHandler 1 public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState 2 { 3 //... 4 private ControllerBuilder _controllerBuilder; 5 internal Controller

ASP.NET Web API 控制器创建过程(二)

ASP.NET Web API 控制器创建过程(二) 前言 本来这篇随笔应该是在上周就该写出来公布的,因为身体跟不上节奏感冒发烧有心无力,这样的天气感冒发烧生不如死,也真正的体会到了什么叫病来如山倒,病去如抽丝.这两天状态才好了一点,让我理解了什么才是革命的本钱,希望大家也多保重身体. 好了,还是回归主题,对于上一篇的内容解说的仅仅是ASP.NET Web API控制器创建过程中的一个局部知识,在接着上篇内容解说的之前,我会先回想一下上篇的内容,而且在本篇里进行整合,让我们要看到的是一个整个的创

ASP.NET Web API 控制器创建过程(一)

ASP.NET Web API 控制器创建过程(一) 前言 在前面对管道.路由有了基础的了解过后,本篇将带大家一起学习一下在ASP.NET Web API中控制器的创建过程,这过程分为几个部分下面的内容会为大家讲解第一个部分,也是ASP.NET Web API框架跟ASP.NET MVC框架实现上存在不同的一部分. ASP.NET Web API 控制器创建.激活过程 ASP.NET Web API 控制器创建过程(一) ASP.NET Web API 控制器创建过程(二) 未完待续 环境描述.

ios view的创建过程

师傅发我一堆view的创建函数,目的让我知道view的创建过程. - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization } return self; } - (void)viewW

ASP.NETWeb API 控制器创建过程(二)

ASP.NET Web API 控制器创建过程(二) 前言 本来这篇随笔应该是在上周就该写出来发布的,由于身体跟不上节奏感冒发烧有心无力,这种天气感冒发烧生不如死,也真正的体会到了什么叫病来如山倒,病去如抽丝.这两天状态才好了一点,让我理解了什么才是革命的本钱,希望大家也多保重身体. 好了,还是回归主题,对于上一篇的内容讲解的只是ASP.NET Web API控制器创建过程中的一个局部知识,在接着上篇内容讲解的之前,我会先回顾一下上篇的内容,并且在本篇里进行整合,让我们要看到的是一个整个的创建过

Android4.4 Framework分析——Activity窗口的创建过程(一)

学习android的窗口模块一周多了,感觉自己对这个模块的理解还是比较模糊,先把get的知识点记录一下. 下图是学习过程记录的activity窗口启动过程序列图,没有或者没办法完整的描绘出来,整个过程比较复杂: 整个学习过程中是参照老罗的android之旅博客和<深入理解android内核设计思想>一书来辅助的,非常感谢前辈. Activity的整体启动过程可查看Android4.4 framework分析--Launcher中启动应用程序(startActivity)的过程的序列图,本文关注