当前位置: 移动技术网 > IT编程>开发语言>.net > Spring.Net是怎么在MVC中实现注入的(原理)

Spring.Net是怎么在MVC中实现注入的(原理)

2019年09月10日  | 移动技术网IT编程  | 我要评论

杜聿明,初中女生照片,快乐大本营20101219

本文将介绍spring.net(不仅仅是spring.net,其实所有的ioc容器要向控制器中进行注入,原理都是差不多的)在mvc控制器中依赖注入的实现原理,本文并没有关于在mvc使用spring怎么配置,怎么使用,怎么实现。

引言放在前面,只是为了避免浪费你的时间。

望你能静心片刻,认真阅读。

防止爬虫,加个链接:https://www.cnblogs.com/medlarcanfly/p/11488689.html

情景

1     public class homecontroller : controller
2     {
3         //这是一个很神奇的注入
4         private ibll.iuserinfoservice userinfoservice { get; set; }
5         public actionresult index()
6         {
7             return content(userinfoservice.getname());
8         }
9     }

 

每次看代码都有不一样的理解,今天我在看mvc控制器中一个通过spring.net依赖注入的userinfoservice属性时,突然有些疑问,注入的前提是控制反转,这么说我的controller是从ioc容器中来的了?但是我不记得在哪个地方有配置额,对此我展开了深入的研究。

从mvc本身开始

首先我们要搞懂mvc本身是通过什么方式获取控制器对象的,本质如果都没有搞懂,又何来扩展呢?

在mvc模式下,通过实现icontrollerfactory接口的对象来获取当前请求的控制器对象,实现icontrollerfactory接口的对象也就是控制器的创建工厂。

简单看下icontrollerfactory

 1     //
 2     // 摘要:
 3     //     定义控制器工厂所需的方法。
 4     public interface icontrollerfactory
 5     {
 6         //
 7         // 摘要:
 8         //     使用指定的请求上下文来创建指定的控制器。
 9         //
10         // 参数:
11         //   requestcontext:
12         //     请求上下文。
13         //
14         //   controllername:
15         //     控制器的名称。
16         //
17         // 返回结果:
18         //     控制器。
19         icontroller createcontroller(requestcontext requestcontext, string controllername);
20         //
21         // 摘要:
22         //     获取控制器的会话行为。
23         //
24         // 参数:
25         //   requestcontext:
26         //     请求上下文。
27         //
28         //   controllername:
29         //     你想要获取器其会话行为的控制器的名称。
30         //
31         // 返回结果:
32         //     控制器的会话行为。
33         sessionstatebehavior getcontrollersessionbehavior(requestcontext requestcontext, string controllername);
34         //
35         // 摘要:
36         //     释放指定的控制器。
37         //
38         // 参数:
39         //   controller:
40         //     控制器。
41         void releasecontroller(icontroller controller);
42     }

 

一个http请求过来,选择哪个控制器是通过mvchandler来处理的

控制器工厂是通过controllerbuilder的current属性提供给mvchandler使用的

下面的代码是反编译过来的,简单看下即可(因为我要标记黄色高亮部分,所以没有折叠)

 1 internal controllerbuilder controllerbuilder
 2 {
 3     get
 4     {
 5         if (this._controllerbuilder == null)
 6         {
 7             this._controllerbuilder = controllerbuilder.current;
 8         }
 9         return this._controllerbuilder;
10     }
11     set
12     {
13         this._controllerbuilder = value;
14     }
15 }
 1 public class mvchandler : ihttpasynchandler, ihttphandler, irequiressessionstate
 2 {
 3     // fields
 4     private controllerbuilder _controllerbuilder;
 5     private static readonly object _processrequesttag;
 6     internal static readonly string mvcversion;
 7     public static readonly string mvcversionheadername;
 8 
 9     // methods
10     static mvchandler();
11     public mvchandler(requestcontext requestcontext);
12     protected internal virtual void addversionheader(httpcontextbase httpcontext);
13     protected virtual iasyncresult beginprocessrequest(httpcontext httpcontext, asynccallback callback, object state);
14     protected internal virtual iasyncresult beginprocessrequest(httpcontextbase httpcontext, asynccallback callback, object state);
15     protected internal virtual void endprocessrequest(iasyncresult asyncresult);
16     private static string getmvcversionstring();
17     protected virtual void processrequest(httpcontext httpcontext);
18     protected internal virtual void processrequest(httpcontextbase httpcontext);
19     private void processrequestinit(httpcontextbase httpcontext, out icontroller controller, out icontrollerfactory factory);
20     private void removeoptionalroutingparameters();
21     iasyncresult ihttpasynchandler.beginprocessrequest(httpcontext context, asynccallback cb, object extradata);
22     void ihttpasynchandler.endprocessrequest(iasyncresult result);
23     void ihttphandler.processrequest(httpcontext httpcontext);
24 
25     // properties
26     internal controllerbuilder controllerbuilder { get; set; }
27     public static bool disablemvcresponseheader { get; [compilergenerated] set; }
28     protected virtual bool isreusable { get; }
29     public requestcontext requestcontext { get; [compilergenerated] private set; }
30     bool ihttphandler.isreusable { get; }
31 
32     // nested types
33     [serializable, compilergenerated]
34     private sealed class <>c
35     {
36         // fields
37         public static readonly mvchandler.<>c <>9;
38         public static begininvokedelegate<mvchandler.processrequeststate> <>9__20_0;
39         public static endinvokevoiddelegate<mvchandler.processrequeststate> <>9__20_1;
40         public static func<keyvaluepair<string, object>, bool> <>9__26_0;
41 
42         // methods
43         static <>c();
44         public <>c();
45         internal iasyncresult <beginprocessrequest>b__20_0(asynccallback asynccallback, object asyncstate, mvchandler.processrequeststate innerstate);
46         internal void <beginprocessrequest>b__20_1(iasyncresult asyncresult, mvchandler.processrequeststate innerstate);
47         internal bool <removeoptionalroutingparameters>b__26_0(keyvaluepair<string, object> entry);
48     }
49 
50     [structlayout(layoutkind.sequential)]
51     private struct processrequeststate
52     {
53         internal iasynccontroller asynccontroller;
54         internal icontrollerfactory factory;
55         internal requestcontext requestcontext;
56         internal void releasecontroller();
57     }
58 }

 

默认工厂

默认情况下,在controllerbuilder内部会创建一个defaultcontrollerfactory类型的对象,以提供处理请求。

defaultcontrollerfactory是实现icontrollerfactory接口的。

  1     //
  2     // 摘要:
  3     //     表示默认情况下已注册的控制器工厂。
  4     public class defaultcontrollerfactory : icontrollerfactory
  5     {
  6         //
  7         // 摘要:
  8         //     初始化 system.web.mvc.defaultcontrollerfactory 类的新实例。
  9         public defaultcontrollerfactory();
 10         //
 11         // 摘要:
 12         //     使用控制器激活器来初始化 system.web.mvc.defaultcontrollerfactory 类的新实例。
 13         //
 14         // 参数:
 15         //   controlleractivator:
 16         //     实现控制器激活器接口的对象。
 17         public defaultcontrollerfactory(icontrolleractivator controlleractivator);
 18 
 19         //
 20         // 摘要:
 21         //     使用指定的请求上下文来创建指定的控制器。
 22         //
 23         // 参数:
 24         //   requestcontext:
 25         //     http 请求的上下文,其中包括 http 上下文和路由数据。
 26         //
 27         //   controllername:
 28         //     控制器的名称。
 29         //
 30         // 返回结果:
 31         //     控制器。
 32         //
 33         // 异常:
 34         //   t:system.argumentnullexception:
 35         //     requestcontext 参数为 null。
 36         //
 37         //   t:system.argumentexception:
 38         //     controllername 参数为 null 或为空。
 39         public virtual icontroller createcontroller(requestcontext requestcontext, string controllername);
 40         //
 41         // 摘要:
 42         //     释放指定的控制器。
 43         //
 44         // 参数:
 45         //   controller:
 46         //     要释放的控制器。
 47         public virtual void releasecontroller(icontroller controller);
 48         //
 49         // 摘要:
 50         //     检索指定请求上下文和控制器类型的控制器实例。
 51         //
 52         // 参数:
 53         //   requestcontext:
 54         //     http 请求的上下文,其中包括 http 上下文和路由数据。
 55         //
 56         //   controllertype:
 57         //     控制器的类型。
 58         //
 59         // 返回结果:
 60         //     控制器实例。
 61         //
 62         // 异常:
 63         //   t:system.web.httpexception:
 64         //     controllertype 为 null。
 65         //
 66         //   t:system.argumentexception:
 67         //     无法分配 controllertype。
 68         //
 69         //   t:system.invalidoperationexception:
 70         //     无法创建 controllertype 的实例。
 71         protected internal virtual icontroller getcontrollerinstance(requestcontext requestcontext, type controllertype);
 72         //
 73         // 摘要:
 74         //     返回控制器的会话行为。
 75         //
 76         // 参数:
 77         //   requestcontext:
 78         //     请求上下文。
 79         //
 80         //   controllertype:
 81         //     控制器的类型。
 82         //
 83         // 返回结果:
 84         //     控制器的会话行为。
 85         protected internal virtual sessionstatebehavior getcontrollersessionbehavior(requestcontext requestcontext, type controllertype);
 86         //
 87         // 摘要:
 88         //     检索指定名称和请求上下文的控制器类型。
 89         //
 90         // 参数:
 91         //   requestcontext:
 92         //     http 请求的上下文,其中包括 http 上下文和路由数据。
 93         //
 94         //   controllername:
 95         //     控制器的名称。
 96         //
 97         // 返回结果:
 98         //     控制器类型。
 99         protected internal virtual type getcontrollertype(requestcontext requestcontext, string controllername);
100     }

 

默认情况下,controller类需要提供默认的构造函数,因为defaultcontrollerfactory是通过反射来创建controller对象实例的。

如果我们定义的controller需要通过构造函数创建,或者通过某个ioc容器管理controller,可以通过自定义控制器工厂来实现。

自定义控制器工厂

为什么说这么多关于控制器工厂的东西呢,其实spring.net就是通过继承defaultcontrollerfactory创建springcontrollerfactory的。

说了这么多就是为了后面可以更容易的理解spring.net的控制器工厂源码罢了。

回归正题,接着创建自己的控制器工厂。

1.home控制器内容如下

 1     public class homecontroller : controller
 2     {
 3         private iuserinfoservice userinfoservice { get; set; }
 4         public homecontroller(iuserinfoservice userinfoservice)
 5         {
 6             userinfoservice = userinfoservice;
 7         }
 8         public actionresult index()
 9         {
10             return content(userinfoservice.getname());
11         }
12     }

 

这里的userinfoservice只是一个很简陋的测试类,只有一个getname()方法用来返回“小明”。

接下来将通过自定义控制器工厂实现构造注入userinfoservice

2.创建控制器工厂mycontrollerfactory

为了方便我直接继承了defaultcontrollerfactory,当然也可以通过实现icontrollerfactory来创建

 1     public class mycontrollerfactory : defaultcontrollerfactory
 2     {
 3         private static readonly ibll.iuserinfoservice userinfoservice = new bll.userinfoservice();
 4 
 5         //重写createcontroller
 6         public override icontroller createcontroller(requestcontext requestcontext, string controllername)
 7         {
 8             icontroller controller = null;
 9             if (controllername == "home")
10             {
11                 //如果是我们制定的home控制器则给其实例化,并通过构造参数注入userinfoservice
12                 controller = new homecontroller(userinfoservice);
13             }
14             else
15             {
16                 //通过默认控制器工厂创建控制器
17                 controller = base.createcontroller(requestcontext, controllername);
18             }
19             return controller;
20         }
21     }

 

3.在global.asax中注册

1         protected void application_start()
2         {
3             mycontrollerfactory mycontrollerfactory = new mycontrollerfactory();
4             //通过controllerbuilder设置制定的控制器工厂
5             controllerbuilder.current.setcontrollerfactory(mycontrollerfactory);
6             arearegistration.registerallareas();
7             routeconfig.registerroutes(routetable.routes);
8         }

 

4.运行测试(神奇不再神奇)

 

意料之外,情理之中,我们并没有在控制器中实例化,结果却出来了

(实例化在工厂中完成了)

 

spring.net注入原理

说了这么多,回头看看标题“spring.net是怎么在mvc中实现注入的”,你倒是说啊,等的花都谢了,连spring.net的毛都没看到.....

其实,如果你是认真读过来的,答案在你心中应该已经有了。

打开折叠,就是答案

  1 namespace spring.web.mvc
  2 {
  3     /// <summary>
  4     /// controller factory for asp.net mvc
  5     /// </summary>
  6     public class springcontrollerfactory : defaultcontrollerfactory
  7     {
  8         private static iapplicationcontext _context;
  9 
 10         /// <summary>
 11         /// gets the application context.
 12         /// </summary>
 13         /// <value>the application context.</value>
 14         public static iapplicationcontext applicationcontext
 15         {
 16             get
 17             {
 18                 if (_context == null || _context.name != applicationcontextname)
 19                 {
 20                     if (string.isnullorempty(applicationcontextname))
 21                     {
 22                         _context = contextregistry.getcontext();
 23                     }
 24                     else
 25                     {
 26                         _context = contextregistry.getcontext(applicationcontextname);
 27                     }
 28                 }
 29 
 30                 return _context;
 31             }
 32         }
 33 
 34         /// <summary>
 35         /// gets or sets the name of the application context.
 36         /// </summary>
 37         /// <remarks>
 38         /// defaults to using the root (default) application context.
 39         /// </remarks>
 40         /// <value>the name of the application context.</value>
 41         public static string applicationcontextname { get; set; }
 42 
 43         /// <summary>
 44         /// creates the specified controller by using the specified request context.
 45         /// </summary>
 46         /// <param name="requestcontext">the context of the http request, which includes the http context and route data.</param>
 47         /// <param name="controllername">the name of the controller.</param>
 48         /// <returns>a reference to the controller.</returns>
 49         /// <exception cref="t:system.argumentnullexception">the <paramref name="requestcontext"/> parameter is null.</exception>
 50         /// <exception cref="t:system.argumentexception">the <paramref name="controllername"/> parameter is null or empty.</exception>
 51         public override icontroller createcontroller(requestcontext requestcontext, string controllername)
 52         {
 53             icontroller controller;
 54 
 55             if (applicationcontext.containsobjectdefinition(controllername))
 56             {
 57                 controller = applicationcontext.getobject(controllername) as icontroller;
 58             }
 59             else
 60             {
 61                 controller = base.createcontroller(requestcontext, controllername);
 62             }
 63 
 64             addactioninvokerto(controller);
 65 
 66             return controller;
 67         }
 68 
 69         /// <summary>
 70         /// retrieves the controller instance for the specified request context and controller type.
 71         /// </summary>
 72         /// <param name="requestcontext">the context of the http request, which includes the http context and route data.</param>
 73         /// <param name="controllertype">the type of the controller.</param>
 74         /// <returns>the controller instance.</returns>
 75         /// <exception cref="t:system.web.httpexception">
 76         ///     <paramref name="controllertype"/> is null.</exception>
 77         /// <exception cref="t:system.argumentexception">
 78         ///     <paramref name="controllertype"/> cannot be assigned.</exception>
 79         /// <exception cref="t:system.invalidoperationexception">an instance of <paramref name="controllertype"/> cannot be created.</exception>
 80         protected override icontroller getcontrollerinstance(requestcontext requestcontext, type controllertype)
 81         {
 82             icontroller controller = null;
 83 
 84             if (controllertype != null)
 85             {
 86                 var controllers = applicationcontext.getobjectsoftype(controllertype);
 87                 if (controllers.count > 0)
 88                 {
 89                     controller = (icontroller)controllers.first().value;
 90                 }
 91             }
 92 
 93             if (controller == null)
 94             {
 95                 //pass to base class for remainder of handling if can't find it in the context
 96                 controller = base.getcontrollerinstance(requestcontext, controllertype);
 97             }
 98             
 99             addactioninvokerto(controller);
100 
101             return controller;
102         }
103 
104         /// <summary>
105         /// adds the action invoker to the controller instance.
106         /// </summary>
107         /// <param name="controller">the controller.</param>
108         protected virtual void addactioninvokerto(icontroller controller)
109         {
110             if (controller == null)
111                 return;
112 
113             if (typeof(controller).isassignablefrom(controller.gettype()))
114             {
115                 ((controller)controller).actioninvoker = new springactioninvoker(applicationcontext);
116             }
117         }
118 
119     }
120 }

 

关于代码我想就不用过多解释了,有了上面的知识基础,这就是一看就懂的那种。

算了,我还是说一下createcontroller方法吧,防止有不熟悉spring.net的小伙伴。

 

applicationcontext:这就是相当于ioc容器的东西

applicationcontext.containsobjectdefinition(controllername):返回容器中是否存在名称为controllername的对象

 

总结

仔细品味每一行代码,会发现任何东西都没有表面上那么简单,每一个实现的背后都值得深入研究。

码了这么长时间,希望能对正在阅读的你有所帮助。

 

参考书籍:《asp.net本质论》

 

如有说的不清楚或者错误的地方,还望指正

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网