欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring.Net在MVC中實現(xiàn)注入的原理解析

 更新時間:2019年09月10日 08:23:25   作者:MedlarCanFly  
這篇文章主要介紹了Spring.Net在MVC中實現(xiàn)注入的原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下

前言

本文將介紹Spring.Net(不僅僅是Spring.Net,其實所有的IoC容器要向控制器中進(jìn)行注入,原理都是差不多的)在MVC控制器中依賴注入的實現(xiàn)原理,本文并沒有關(guān)于在MVC使用Spring怎么配置,怎么使用,怎么實現(xiàn)。

引言放在前面,只是為了避免浪費(fèi)你的時間。

望你能靜心片刻,認(rèn)真閱讀。

情景

public class HomeController : Controller
  {
    //這是一個很神奇的注入
    private IBLL.IUserInfoService UserInfoService { get; set; }
    public ActionResult Index()
    {
      return Content(UserInfoService.GetName());
    }
  }

每次看代碼都有不一樣的理解,今天我在看MVC控制器中一個通過Spring.Net依賴注入的UserInfoService屬性時,突然有些疑問,注入的前提是控制反轉(zhuǎn),這么說我的Controller是從IoC容器中來的了?但是我不記得在哪個地方有配置額,對此我展開了深入的研究。

從MVC本身開始

首先我們要搞懂MVC本身是通過什么方式獲取控制器對象的,本質(zhì)如果都沒有搞懂,又何來擴(kuò)展呢?

在MVC模式下,通過實現(xiàn)IControllerFactory接口的對象來獲取當(dāng)前請求的控制器對象,實現(xiàn)IControllerFactory接口的對象也就是控制器的創(chuàng)建工廠。

簡單看下IControllerFactory

//
  // 摘要:
  //   定義控制器工廠所需的方法。
  public interface IControllerFactory
  {
    //
    // 摘要:
    //   使用指定的請求上下文來創(chuàng)建指定的控制器。
    //
    // 參數(shù):
    //  requestContext:
    //   請求上下文。
    //
    //  controllerName:
    //   控制器的名稱。
    //
    // 返回結(jié)果:
    //   控制器。
    IController CreateController(RequestContext requestContext, string controllerName);
    //
    // 摘要:
    //   獲取控制器的會話行為。
    //
    // 參數(shù):
    //  requestContext:
    //   請求上下文。
    //
    //  controllerName:
    //   你想要獲取器其會話行為的控制器的名稱。
    //
    // 返回結(jié)果:
    //   控制器的會話行為。
    SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName);
    //
    // 摘要:
    //   釋放指定的控制器。
    //
    // 參數(shù):
    //  controller:
    //   控制器。
    void ReleaseController(IController controller);
  }

一個Http請求過來,選擇哪個控制器是通過MvcHandler來處理的

控制器工廠是通過ControllerBuilder的Current屬性提供給MvcHandler使用的

下面的代碼是反編譯過來的,簡單看下即可(因為我要標(biāo)記黃色高亮部分,所以沒有折疊)

internal ControllerBuilder ControllerBuilder
{
  get
  {
    if (this._controllerBuilder == null)
    {
      this._controllerBuilder = ControllerBuilder.Current;
    }
    return this._controllerBuilder;
  }
  set
  {
    this._controllerBuilder = value;
  }
}
public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState
{
  // Fields
  private ControllerBuilder _controllerBuilder;
  private static readonly object _processRequestTag;
  internal static readonly string MvcVersion;
  public static readonly string MvcVersionHeaderName;

  // Methods
  static MvcHandler();
  public MvcHandler(RequestContext requestContext);
  protected internal virtual void AddVersionHeader(HttpContextBase httpContext);
  protected virtual IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state);
  protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state);
  protected internal virtual void EndProcessRequest(IAsyncResult asyncResult);
  private static string GetMvcVersionString();
  protected virtual void ProcessRequest(HttpContext httpContext);
  protected internal virtual void ProcessRequest(HttpContextBase httpContext);
  private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory);
  private void RemoveOptionalRoutingParameters();
  IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData);
  void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result);
  void IHttpHandler.ProcessRequest(HttpContext httpContext);

  // Properties
  internal ControllerBuilder ControllerBuilder { get; set; }
  public static bool DisableMvcResponseHeader { get; [CompilerGenerated] set; }
  protected virtual bool IsReusable { get; }
  public RequestContext RequestContext { get; [CompilerGenerated] private set; }
  bool IHttpHandler.IsReusable { get; }

  // Nested Types
  [Serializable, CompilerGenerated]
  private sealed class <>c
  {
    // Fields
    public static readonly MvcHandler.<>c <>9;
    public static BeginInvokeDelegate<MvcHandler.ProcessRequestState> <>9__20_0;
    public static EndInvokeVoidDelegate<MvcHandler.ProcessRequestState> <>9__20_1;
    public static Func<KeyValuePair<string, object>, bool> <>9__26_0;

    // Methods
    static <>c();
    public <>c();
    internal IAsyncResult <BeginProcessRequest>b__20_0(AsyncCallback asyncCallback, object asyncState, MvcHandler.ProcessRequestState innerState);
    internal void <BeginProcessRequest>b__20_1(IAsyncResult asyncResult, MvcHandler.ProcessRequestState innerState);
    internal bool <RemoveOptionalRoutingParameters>b__26_0(KeyValuePair<string, object> entry);
  }

  [StructLayout(LayoutKind.Sequential)]
  private struct ProcessRequestState
  {
    internal IAsyncController AsyncController;
    internal IControllerFactory Factory;
    internal RequestContext RequestContext;
    internal void ReleaseController();
  }
}

默認(rèn)工廠

默認(rèn)情況下,在ControllerBuilder內(nèi)部會創(chuàng)建一個DefaultControllerFactory類型的對象,以提供處理請求。

DefaultControllerFactory是實現(xiàn)IControllerFactory接口的。

//
  // 摘要:
  //   表示默認(rèn)情況下已注冊的控制器工廠。
  public class DefaultControllerFactory : IControllerFactory
  {
    //
    // 摘要:
    //   初始化 System.Web.Mvc.DefaultControllerFactory 類的新實例。
    public DefaultControllerFactory();
    //
    // 摘要:
    //   使用控制器激活器來初始化 System.Web.Mvc.DefaultControllerFactory 類的新實例。
    //
    // 參數(shù):
    //  controllerActivator:
    //   實現(xiàn)控制器激活器接口的對象。
    public DefaultControllerFactory(IControllerActivator controllerActivator);

    //
    // 摘要:
    //   使用指定的請求上下文來創(chuàng)建指定的控制器。
    //
    // 參數(shù):
    //  requestContext:
    //   HTTP 請求的上下文,其中包括 HTTP 上下文和路由數(shù)據(jù)。
    //
    //  controllerName:
    //   控制器的名稱。
    //
    // 返回結(jié)果:
    //   控制器。
    //
    // 異常:
    //  T:System.ArgumentNullException:
    //   requestContext 參數(shù)為 null。
    //
    //  T:System.ArgumentException:
    //   controllerName 參數(shù)為 null 或為空。
    public virtual IController CreateController(RequestContext requestContext, string controllerName);
    //
    // 摘要:
    //   釋放指定的控制器。
    //
    // 參數(shù):
    //  controller:
    //   要釋放的控制器。
    public virtual void ReleaseController(IController controller);
    //
    // 摘要:
    //   檢索指定請求上下文和控制器類型的控制器實例。
    //
    // 參數(shù):
    //  requestContext:
    //   HTTP 請求的上下文,其中包括 HTTP 上下文和路由數(shù)據(jù)。
    //
    //  controllerType:
    //   控制器的類型。
    //
    // 返回結(jié)果:
    //   控制器實例。
    //
    // 異常:
    //  T:System.Web.HttpException:
    //   controllerType 為 null。
    //
    //  T:System.ArgumentException:
    //   無法分配 controllerType。
    //
    //  T:System.InvalidOperationException:
    //   無法創(chuàng)建 controllerType 的實例。
    protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType);
    //
    // 摘要:
    //   返回控制器的會話行為。
    //
    // 參數(shù):
    //  requestContext:
    //   請求上下文。
    //
    //  controllerType:
    //   控制器的類型。
    //
    // 返回結(jié)果:
    //   控制器的會話行為。
    protected internal virtual SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType);
    //
    // 摘要:
    //   檢索指定名稱和請求上下文的控制器類型。
    //
    // 參數(shù):
    //  requestContext:
    //   HTTP 請求的上下文,其中包括 HTTP 上下文和路由數(shù)據(jù)。
    //
    //  controllerName:
    //   控制器的名稱。
    //
    // 返回結(jié)果:
    //   控制器類型。
    protected internal virtual Type GetControllerType(RequestContext requestContext, string controllerName);
  }

默認(rèn)情況下,Controller類需要提供默認(rèn)的構(gòu)造函數(shù),因為DefaultControllerFactory是通過反射來創(chuàng)建Controller對象實例的。

如果我們定義的Controller需要通過構(gòu)造函數(shù)創(chuàng)建,或者通過某個IoC容器管理Controller,可以通過自定義控制器工廠來實現(xiàn)。

自定義控制器工廠

為什么說這么多關(guān)于控制器工廠的東西呢,其實Spring.Net就是通過繼承DefaultControllerFactory創(chuàng)建SpringControllerFactory的。

說了這么多就是為了后面可以更容易的理解Spring.Net的控制器工廠源碼罷了。

回歸正題,接著創(chuàng)建自己的控制器工廠。

1.Home控制器內(nèi)容如下

public class HomeController : Controller
  {
    private IUserInfoService UserInfoService { get; set; }
    public HomeController(IUserInfoService userInfoService)
    {
      UserInfoService = userInfoService;
    }
    public ActionResult Index()
    {
      return Content(UserInfoService.GetName());
    }
  }

這里的UserInfoService只是一個很簡陋的測試類,只有一個GetName()方法用來返回“小明”。

接下來將通過自定義控制器工廠實現(xiàn)構(gòu)造注入UserInfoService

2.創(chuàng)建控制器工廠MyControllerFactory

為了方便我直接繼承了DefaultControllerFactory,當(dāng)然也可以通過實現(xiàn)IControllerFactory來創(chuàng)建

public class MyControllerFactory : DefaultControllerFactory
  {
    private static readonly IBLL.IUserInfoService userInfoService = new BLL.UserInfoService();

    //重寫CreateController
    public override IController CreateController(RequestContext requestContext, string controllerName)
    {
      IController controller = null;
      if (controllerName == "Home")
      {
        //如果是我們制定的Home控制器則給其實例化,并通過構(gòu)造參數(shù)注入userInfoService
        controller = new HomeController(userInfoService);
      }
      else
      {
        //通過默認(rèn)控制器工廠創(chuàng)建控制器
        controller = base.CreateController(requestContext, controllerName);
      }
      return controller;
    }
  }

3.在Global.asax中注冊

protected void Application_Start()
    {
      MyControllerFactory myControllerFactory = new MyControllerFactory();
      //通過ControllerBuilder設(shè)置制定的控制器工廠
      ControllerBuilder.Current.SetControllerFactory(myControllerFactory);
      AreaRegistration.RegisterAllAreas();
      RouteConfig.RegisterRoutes(RouteTable.Routes);
    }

4.運(yùn)行測試(神奇不再神奇)

意料之外,情理之中,我們并沒有在控制器中實例化,結(jié)果卻出來了

(實例化在工廠中完成了)

Spring.Net注入原理

說了這么多,回頭看看標(biāo)題“Spring.Net是怎么在MVC中實現(xiàn)注入的”,你倒是說啊,等的花都謝了,連Spring.Net的毛都沒看到.....

其實,如果你是認(rèn)真讀過來的,答案在你心中應(yīng)該已經(jīng)有了。

答案如下

namespace Spring.Web.Mvc
{
  /// <summary>
  /// Controller Factory for ASP.NET MVC
  /// </summary>
  public class SpringControllerFactory : DefaultControllerFactory
  {
    private static IApplicationContext _context;

    /// <summary>
    /// Gets the application context.
    /// </summary>
    /// <value>The application context.</value>
    public static IApplicationContext ApplicationContext
    {
      get
      {
        if (_context == null || _context.Name != ApplicationContextName)
        {
          if (string.IsNullOrEmpty(ApplicationContextName))
          {
            _context = ContextRegistry.GetContext();
          }
          else
          {
            _context = ContextRegistry.GetContext(ApplicationContextName);
          }
        }

        return _context;
      }
    }

    /// <summary>
    /// Gets or sets the name of the application context.
    /// </summary>
    /// <remarks>
    /// Defaults to using the root (default) Application Context.
    /// </remarks>
    /// <value>The name of the application context.</value>
    public static string ApplicationContextName { get; set; }

    /// <summary>
    /// Creates the specified controller by using the specified request context.
    /// </summary>
    /// <param name="requestContext">The context of the HTTP request, which includes the HTTP context and route data.</param>
    /// <param name="controllerName">The name of the controller.</param>
    /// <returns>A reference to the controller.</returns>
    /// <exception cref="T:System.ArgumentNullException">The <paramref name="requestContext"/> parameter is null.</exception>
    /// <exception cref="T:System.ArgumentException">The <paramref name="controllerName"/> parameter is null or empty.</exception>
    public override IController CreateController(RequestContext requestContext, string controllerName)
    {
      IController controller;

      if (ApplicationContext.ContainsObjectDefinition(controllerName))
      {
        controller = ApplicationContext.GetObject(controllerName) as IController;
      }
      else
      {
        controller = base.CreateController(requestContext, controllerName);
      }

      AddActionInvokerTo(controller);

      return controller;
    }

    /// <summary>
    /// Retrieves the controller instance for the specified request context and controller type.
    /// </summary>
    /// <param name="requestContext">The context of the HTTP request, which includes the HTTP context and route data.</param>
    /// <param name="controllerType">The type of the controller.</param>
    /// <returns>The controller instance.</returns>
    /// <exception cref="T:System.Web.HttpException">
    ///   <paramref name="controllerType"/> is null.</exception>
    /// <exception cref="T:System.ArgumentException">
    ///   <paramref name="controllerType"/> cannot be assigned.</exception>
    /// <exception cref="T:System.InvalidOperationException">An instance of <paramref name="controllerType"/> cannot be created.</exception>
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
      IController controller = null;

      if (controllerType != null)
      {
        var controllers = ApplicationContext.GetObjectsOfType(controllerType);
        if (controllers.Count > 0)
        {
          controller = (IController)controllers.First().Value;
        }
      }

      if (controller == null)
      {
        //pass to base class for remainder of handling if can't find it in the context
        controller = base.GetControllerInstance(requestContext, controllerType);
      }
      
      AddActionInvokerTo(controller);

      return controller;
    }

    /// <summary>
    /// Adds the action invoker to the controller instance.
    /// </summary>
    /// <param name="controller">The controller.</param>
    protected virtual void AddActionInvokerTo(IController controller)
    {
      if (controller == null)
        return;

      if (typeof(Controller).IsAssignableFrom(controller.GetType()))
      {
        ((Controller)controller).ActionInvoker = new SpringActionInvoker(ApplicationContext);
      }
    }
  }
}

關(guān)于代碼我想就不用過多解釋了,有了上面的知識基礎(chǔ),這就是一看就懂的那種。

算了,我還是說一下CreateController方法吧,防止有不熟悉Spring.Net的小伙伴。

ApplicationContext:這就是相當(dāng)于IoC容器的東西

ApplicationContext.ContainsObjectDefinition(controllerName):返回容器中是否存在名稱為controllerName的對象

總結(jié)

仔細(xì)品味每一行代碼,會發(fā)現(xiàn)任何東西都沒有表面上那么簡單,每一個實現(xiàn)的背后都值得深入研究。

碼了這么長時間,希望能對正在閱讀的你有所幫助。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Springcloud eureka搭建高可用集群過程圖解

    Springcloud eureka搭建高可用集群過程圖解

    這篇文章主要介紹了Springcloud eureka搭建高可用集群過程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04
  • String s = new String(''a '') 到底產(chǎn)生幾個對象

    String s = new String(''a '') 到底產(chǎn)生幾個對象

    這篇文章主要介紹了String s = new String(" a ") 到底產(chǎn)生幾個對象,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • java連接zookeeper實現(xiàn)zookeeper教程

    java連接zookeeper實現(xiàn)zookeeper教程

    這篇文章主要介紹了java連接zookeeper實現(xiàn)zookeeper教程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Spring MVC 攔截器實現(xiàn)登錄

    Spring MVC 攔截器實現(xiàn)登錄

    這篇文章主要介紹了Spring MVC 攔截器實現(xiàn)登錄,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07
  • Java與SpringBoot對redis的使用方式

    Java與SpringBoot對redis的使用方式

    這篇文章主要介紹了Java與SpringBoot對redis的使用方式,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的朋友可以參考一下
    2022-08-08
  • java 后臺開發(fā)中model與entity(實體類)的區(qū)別說明

    java 后臺開發(fā)中model與entity(實體類)的區(qū)別說明

    這篇文章主要介紹了java 后臺開發(fā)中model與entity(實體類)的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • Java HtmlEmail 郵件發(fā)送的簡單實現(xiàn)代碼

    Java HtmlEmail 郵件發(fā)送的簡單實現(xiàn)代碼

    下面小編就為大家?guī)硪黄狫ava HtmlEmail 郵件發(fā)送的簡單實現(xiàn)代碼。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-06-06
  • 在Spring boot的項目中使用Junit進(jìn)行單體測試

    在Spring boot的項目中使用Junit進(jìn)行單體測試

    今天小編就為大家分享一篇關(guān)于spring boot使用Junit進(jìn)行測試,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Java如何根據(jù)實體指定字段值對其List進(jìn)行排序詳解

    Java如何根據(jù)實體指定字段值對其List進(jìn)行排序詳解

    在Java項目中可能會遇到給出一些條件,將List元素按照給定條件進(jìn)行排序的情況,這篇文章主要給大家介紹了關(guān)于Java如何根據(jù)實體指定字段值對其List進(jìn)行排序的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-07-07
  • Java8新特性之重復(fù)注解與類型注解詳解

    Java8新特性之重復(fù)注解與類型注解詳解

    這篇文章主要使介紹了Java8新特性重復(fù)注解與類型注解,文章還介紹了JDK5中的注解與之對比,感興趣的朋友可以參考下面具體文章內(nèi)容
    2021-09-09

最新評論