rails的自動(dòng)加載模塊

在 rails 的很多模塊定義里經(jīng)??吹竭@樣的代碼:

module Rails
  extend ActiveSupport::Autoload
  autoload :FooBar

看名稱就知道它與自動(dòng)加載有關(guān)。實(shí)際上 ruby 的Kernel模塊里已經(jīng)定義了一個(gè)這樣的方法,autoload(module, filename)這個(gè)方法的作用是當(dāng)?shù)谝淮斡龅街付K時(shí),自動(dòng)按照指定的路徑加載。

為什么 rails 還要再定義一個(gè)這樣的方法呢?原因是為了方便。rails 有大量的模塊分散在不同的文件里,并且這些文件按一定的規(guī)則組織在一起。ActiveSupport::Autoload模塊中的autoload能根據(jù)模塊名稱和約定的規(guī)則生成文件路徑加載模塊,不用每次都指定路徑。除此之外,該模塊還定義了 eager_load! 方法,用于提前加載指定的一組模塊。
其用法如下:

module MyLib
  extend ActiveSupport::Autoload
  autoload :Model

  eager_autoload do
    autoload :Cache
  end
end
MyLib.eager_load!

ActiveSupport::Autoload的源代碼文件在
~/.rvm/gems/ruby-2.4.0/gems activesupport-5.0.1/lib/active_support/dependencies/autoload.rb這是我電腦上的路徑,根據(jù)不同的安裝環(huán)境可能會(huì)有不同。這個(gè)模塊的定義很簡(jiǎn)單,只有70多行,下面對(duì)其主要的方法進(jìn)行分析。

module Autoload
  # 當(dāng)宿主模塊 extend ActiveSupport::Autoload 時(shí),在宿主模塊的上下文中初始化幾個(gè)變量。
  def self.extended(base) # :nodoc:
    base.class_eval do
      @_autoloads = {}  # 保存 eager_load! 所需加載的模塊
      @_under_path = nil  # 保存中間路徑
      @_at_path = nil  # 保存準(zhǔn)確路徑
      @_eager_autoload = false  
    end
  end

  # 該模塊的核心方法,主要作用是生成路徑,并調(diào)用 ruby 自帶的 autoload。
  def autoload(const_name, path = @_at_path)
    unless path
      # 路徑生成規(guī)則,name 為宿主模塊的類方法,返回宿主模塊名稱。
      # 例如在Rails模塊里 autoload :Foo,將返回路徑 Rails/Foo。
      # @_under_path 默認(rèn)是 nil,可通過(guò) autoload_under(path)更改。
      full = [name, @_under_path, const_name.to_s].compact.join("::")
      # 將形如 Rails::Foo::Bar 改為 Rails/Foo/Bar
      path = Inflector.underscore(full)
    end

    # 為 true 時(shí),模塊保存到 @_autoloads,從而可通過(guò) eager_load! 提前加載
    if @_eager_autoload
      @_autoloads[const_name] = path
    end

    # 生成路徑后,調(diào)用 ruby 自帶的 autoload 方法
    super const_name, path
  end

  # 增加中間路徑
  def autoload_under(path)
    @_under_path, old_path = path, @_under_path
    yield
  ensure
    @_under_path = old_path
  end

  # 將模塊加入 @_autoloads,為 eager_load! 作準(zhǔn)備
  def eager_autoload
    old_eager, @_eager_autoload = @_eager_autoload, true
    yield
  ensure
    @_eager_autoload = old_eager
  end

  # 依次加載 @_autoloads 中的模塊
  def eager_load!
    @_autoloads.each_value { |file| require file }
  end
  ......
小結(jié)

ActiveSupport::Autoload按照 Rails 的約定規(guī)則生成路徑自動(dòng)加載模塊。改寫了 autoload方法來(lái)自動(dòng)加載,提供eager_load!方法來(lái)提前加載。生成路徑的規(guī)則為當(dāng)前模塊名/加載模塊名,如有中間路徑,可通過(guò)autoload_under插入。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容