rails2.0.2ソース分析-起動編


  • 前言
  • 本文は主にRuby On Rails 2.0.2のソースコードに対して分析、学習と研究を行う.使用するツールはNetBean 6.1 Beta,WEBRick,SciTE,ruby-debug-base(0.10.0),ruby-debug-ide(0.1.10)です.Rubyバージョンは1.8.6です.どのように分析してまとめるべきか、最初は最も頭が痛いことで、ルビーは対象に向かう言語で、対象の階層から記録しましょう、すべてそんなに直観的ではないようで、1つの巨大なシステムが目の前に置いて、1つのクラス図を整理して、関係図を継承します.ちょっと牛がかぼちゃをかじって、口に入らない感じがします.最后に、Rubyの本质-解釈言语から着手するつもりで、解釈器の角度から出発して、解釈器の歩みに従って、细かく着手して、一歩一歩Railsに深く入り込んで、局部から全体まで、学习の目的を理解します.そこで,最終的には,Railsをソースコードの実行順序の観点から解析することにした.便宜上、NetBeanのデバッグ環境を直接使用し、Rubyが持参したWEBRickを使用して、Railsの最も基本的なruby script/serverに触れることから、まずRailsがどのように起動したのかを見てみましょう.
  • Railsの起動
  • ruby script/serverは、railsをやっている学生たちがよく知っている命令だと思います.serverスクリプトは主に2つのプロセスを実行します:1.Railsを起動します.2.ウェブサーバを起動します(もちろん、WEBRickを起動しました).ここからRailsがどのように起動されたかを見てみましょう.
    前述したように、ソースコードの実行順序の観点から分析するので、Railsが起動したときのコアソースコードの実行順序を見てみましょう.具体的には下図を参照してください(分析を簡単に明らかにするために、重要な本質をつかむために、個人的に起動に関連するソースコードだけを列挙します.実行中、ActiveSupportのcoreに関するextensionのような他のコードはリストされません):
     
      boot.rb  
    ソースパス:RAILS_ROOT/config/boot.rb
     
    このコードファイルはRailsの起動エントリであり、完了した機能は、Railsが起動しているかどうかをまず判断し、起動していない場合はまず「プリ初期化」(preinitialize)プロセスを実行し、その後、起動方式(Vendor/Gem)を選択し、対応するクラス上のrunメソッドを実行することである.メインメソッドboot!コードは次のとおりです.
    def boot!
      unless booted?
        preinitialize
        pick_boot.run
      end
    end

    ここで、初期化プロセスとはRAILS_の実行であるROOT/configディレクトリの下にあるpreinitializer.rb(存在する場合).このプロセスの目的はenvironmentをロードすることです.rbファイルは、いくつかの初期化作業を実行します.参照:http://yudionrails.com/2008/1/7/what-s-new-in-edge-rails-pre-environment-load-hook.このソースコードにはmodule Railsが含まれています.このモジュールの下には、VendorBoot、GemBootの3つのクラスがあります.これらのクラスはBootクラスから継承されています.これは、VendorまたはGemでRailsを起動することを意味します(RALS_ROOT/vender/以下にrailsというディレクトリがある場合は、VendorでRailsを起動します.そうでない場合は、GemからRailsを起動します).Gem方式でRailsを起動すると、どのバージョンのRailsがロードされているかを判断する重要な機能があります.もちろん、私たちが知っているように、environment.rbのRAILS_GEM_VERSIONが働きました.総じて、bootコードの論理は簡単で、難解なものはありません.次に、このファイルの実行論理フローチャート全体を示します.
    initialize.rb  
    ソースパス:gems/rails-2.0.2/lib/initializer.rb(Gem方式起動)
    RAILS_ROOT/vendor/rails/railties/lib/initializer.rb(Vendor方式起動)は、2つの異なる起動方式で実行されるソースコードが異なるが、Railsに必要な構成および初期化を実行する機能は大きく異なる.まず、bootを実行する前のステップを見てみましょう.rbコードの最後のステップ(pick_boot.runを覚えていますか?)具体的なコードは以下の通りです.
     
    class Boot
      def run
        load_initializer
        Rails::Initializer.run(:set_load_path)
      end
    end
    

    bootメソッドの選択が完了すると、対応するBootオブジェクトのrunメソッドが実行され、runメソッドはまず初期化器にロードされ、VendorRootは次のようにロードされます.
    class VendorBoot < Boot
      def load_initializer
        require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
      end
    end
    

    GemRootは次のようにロードされます.
    class GemBoot < Boot
      def load_initializer
        self.class.load_rubygems
        load_rails_gem
        require 'initializer'
      end
      ...
    end
    

    OK.イニシエータのロードが完了すると、Bootのrunメソッドはすぐにイニシエータオブジェクトのクラスメソッドrunを実行します.ここでrunメソッドパラメータはset_です.load_path記号.では、initializeに深く入り込むことができます.rbの中で最後まで見に行きました.  initialize.rbにはmodule Railsが定義されており、このコードファイルで最も重要な2つのクラス:ConfigurationとInitializerが含まれています.クラス名から,InitializerクラスはRailsの初期化作業を完了することが明らかになった.もちろん,このプロセスには様々な構成,パラメータが必要であり,これらはConfigurationによって提供される.では、まずコンフィギュレーションがRailsに必要な構成パラメータを提供しているかを見てみましょう.詳細は次の表を参照してください.
    コンフィギュレーション名(accessor名)
    具体的な説明
    frameworks
    読み込まれるRailsフレームワークコンポーネントのリスト、action_を含むcontroller,action_view等
    load_paths
    追加のloadパスリスト、app/controller;app/modelsなどRailsプロジェクトの下のディレクトリ
    load_once_paths
    Railsは1回のディレクトリしかloadできません.現在のバージョンのRailsではこのパラメータは使用されていないようです.
    log_path
    ログファイルのパスは、現在の環境(development,test,production)によって決定されます.
    log_level
    Railsログのログレベル(info,debug)
    view_path
    viewのディレクトリパス、デフォルトパスはapp/viewです
    controller_paths
    controllerのディレクトリパス、デフォルトパスはapp/controller
    cache_classes
    クラスをキャッシュするかどうか.現在使用されていません(falseのままです)
    whiny_nils
    true/false、trueに設定するとRailsでnilメソッドを呼び出すと警告されます
    plugins
    読み込まれたプラグインのリスト、デフォルトは空です
    plugin_paths
    プラグインパス、デフォルトはRAILS_ROOT/vendor/pluginsディレクトリ
    plugin_locators
    プラグインのロケータ、デフォルトはPlugin::FileSystemLocator
    plugin_loader
    プラグインのローダ、デフォルトはPlugin::Loader
    database_configuration_file
    データベースプロファイル、デフォルトはRAILS_ROOT/config/database.yml
    ぐるっと回って、Initializerクラスのrunメソッド(boot.rb呼び出し:Rails::Initializer.run(:set_load_path))に戻りましょう.非常に簡単です.
    def self.run(command = :process, configuration = Configuration.new)
      yield configuration if block_given?
      initializer = new configuration
      initializer.send(command)
      initializer
    end
    

    ブロック(boot.rbが呼び出すときも確かにブロックに関連付けられていない)はともかく、次の作業は新しいConfigurationオブジェクトを生成し、Initializerの構造関数(その後、Initializerオブジェクトによって構成オブジェクトを保存)に割り当て、initializer上のcommandメソッドを実行し、デフォルトはprocessメソッドを実行し、ここでboot.rbの呼び出しはset_を実行しますload_pathメソッド.ここで注目すべきは、新しく生成されたコンフィギュレーションオブジェクトのすべての構成パラメータがデフォルト値であることです.たとえば、frameworksパラメータは次の方法でデフォルト値を取得します.
    def default_frameworks
      [ :active_record, :action_controller, :action_view, :action_mailer, :active_resource ]
    end
    

    controller_pathパラメータは、次の方法でデフォルト値を取得します.
     
    def default_controller_paths
      paths = [File.join(root_path, 'app', 'controllers')]
      paths.concat builtin_directories
      paths
    end
    

    実は、これらの構成はすべて固定されていません.私たちはenviromentにいます.rbでは、次のように定義されています.
    Rails::Initializer.run do |config|
      config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
      config.plugins = [ :exception_notification, :ssl_requirement, :all ]
      ...
    end
    

    ここまで、initializer.rbの紹介は一旦終わり、簡単にset_を実行しただけですload_pathメソッドはloadパスを設定します.次に、実行プロセスはscript/serverに戻ります.
    require File.dirname(__FILE__) + '/../config/boot'
    require 'commands/server'
    

    2番目の文を実行します.次はserverの番です.rbが出場しました.
      server.rb
    ソースコードパス:gems/rails-2.0.2/lib/commands/server.rb   server.rbは主に2つの機能を完成する:1.Active_のロードsupport;2.Webサーバをロードします.Active_のロードsupportは非常に簡単ですが、ソースコードから始まる最初の文です.
    require 'active_support'

    Webサーバのロードは複雑です.まず、RailsはFastCGIをロードしようとし、次のコードに示すようにmongrelをロードしようとします.
    begin
      require_library_or_gem 'fcgi'
    rescue Exception
      # FCGI not available
    end
    
    begin
      require_library_or_gem 'mongrel'
    rescue Exception
      # Mongrel not available
    end
    

    最終的には、defined?(Mongrel)とdefined?(FCGI)では、どのサーバを使用するかを決定します.もちろん,WEBサーバとしてWEBRickを用いることは前述したが,ここで最終的にロードされるサーバは当然webrickである.server.rbの最後のコード:
    require "commands/servers/#{server}" 
    

    ここで#{server}はもちろんwebrickなので、次に実行するのはwebrickである.rb
     
    webrick.rb
    ソースパス:gems/rails-2.0.2/lib/commands/servers/webrick.rb   webrick.rbは以下のいくつかの主要な機能を完成する:1.Rubyが持っているwebrickライブラリをロードします.2.environmentをロードします.rb;3.webrick_のロードserver.rb;4.DispatchServicelet(webrick_server.rbで定義)のクラスメソッドdispatchを実行します.プロセス全体が順次完了するので、概略的なソースコードは以下のようになります.
      require 'webrick'
      require RAILS_ROOT + "/config/environment"
      require 'webrick_server'
      DispatchServlet.dispatch(OPTIONS)

      environment.rb
    ソースパス:RAILS_ROOT/config/environment.rbは私たちがよく知っているenvironmentに戻りました.rbでは,ここでRailsが実行する環境を構成することができ,ここではあまり説明せず,関連するRailsドキュメントに参加することができる.
      webrick_server.rb
    ソースパス:gems/rails-2.0.2/lib/webrick_server.rbこれはRailsが起動して実行した最後のソースファイルです.前述したように、このソースファイルにはDispatchServiceletが定義されています.これは、ブラウザの要求dispatchを対応するcontroller、actionに渡すためのカスタムdispatch servletです.ここではRailsの起動だけを紹介するつもりなので、以下のコードに注目するだけでいいです.
    class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
    
      # Start the WEBrick server with the given options, mounting the
      # DispatchServlet at <tt>/</tt>.
      def self.dispatch(options = {})
        Socket.do_not_reverse_lookup = true # patch for OS X
    
        params = { :Port        => options[:port].to_i,
                   :ServerType  => options[:server_type],
                   :BindAddress => options[:ip] }
        params[:MimeTypes] = options[:mime_types] if options[:mime_types]
    
        server = WEBrick::HTTPServer.new(params)
        server.mount('/', DispatchServlet, options)
    
       trap("INT") { server.shutdown }
        server.start
      end
    end
    

    これは古典的なWEBRickサーバの起動方法であり、あまり説明する必要はなく、webrickの関連ドキュメントを参照することができます.もちろん、webrick_server.rbファイルにはかなり重要なクラスCGIがあり、DispatchServeretクラスにはいくつかの重要な方法があり、私たちはしばらく彼らをそばに置くことができます.後でRailsをさらに分析するときに説明します.  OK.これでRailsは本格的に登場し、webサーバも起動しました.次のことは、もちろんwebサーバがrequestをRailsに転送して処理するのを待っています.国際的な慣例に従って、これはもちろん以下の分解のことです.
    回転:http://www.iteye.com/topic/170683