日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Ruby On Rails-2.0.2源代码分析(1)-Rails的启动

發布時間:2023/12/14 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Ruby On Rails-2.0.2源代码分析(1)-Rails的启动 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
  • 前言

? 本文主要是針對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。
? 應該怎么分析總結,是開始最令人頭痛的事,Ruby是面向對象的語言,從對象的層次記錄吧,似乎一切都不那么直觀,一個龐大的系統擺在眼前,整理一個類圖,繼承關系圖。。。有點牛啃南瓜,無從下口的感覺。最后,決定打算從Ruby的本質-解釋語言下手,從解釋器的角度出發,跟著解釋器的步伐,從細微入手,一步一步深入Rails,以達到從局部到整體,了解學習的目的。所以,最終,我決定從源代碼執行順序的角度去分析Rails。
? 為方便起見,我直接使用NetBean的調試環境,使用Ruby自帶的WEBRick,從接觸Rails最基本的ruby script/server開始,首先來看Rails是怎么啟動起來的。

  • Rails的啟動

? ruby script/server,應該是搞rails的同學們耳熟能詳的命令了。server腳本主要執行兩個的過程:1.啟動Rails;2.啟動web服務器(當然,我這里是啟動WEBRick了)。我們就從這里入手,看看Rails是怎么樣被啟動起來的。
? 前面我說過,我將從源代碼執行順序的角度去分析,所以,讓我們先來看一看Rails啟動時,核心源代碼的執行順序,具體見下圖(為了使得分析簡單明了,抓住關鍵本質所在,我只把個人認為與啟動有關的源代碼列出來,執行過程中,其他類似關于ActiveSupport中關于core的extension之類的代碼就不列出):

? boot.rb

??源代碼路徑:RAILS_ROOT/config/boot.rb
? 這個代碼文件是Rails的啟動入口,完成的功能是:首先判斷Rails是否啟動,如果未啟動則先執行一個“預初始化”(preinitialize)過程,然后選擇一種啟動方式(Vendor/Gem),執行相應類上的run方法。主方法boot!代碼如下:

Ruby代碼 ?
  • 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,他們都繼承自Boot類,分別代表是通過Vendor還是Gem的方式啟動Rails(如果RAILS_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方式啟動)

    ? 雖然兩種不同啟動方式執行的源代碼不同,但是他們完成的功能都大同小異,都對Rails執行必要的配置以及初始化。我們先來看看上一步--執行boot.rb代碼的最后一步(還記得pick_boot.run么?),具體代碼如下:

    ?

    Ruby代碼 ?
  • class?Boot??
  • ??def?run??
  • ????load_initializer??
  • ????Rails::Initializer.run(:set_load_path)??
  • ??end??
  • end??
  • 當完成了選擇一個boot方式后,會執行相應Boot對象的run方法,那么run方法首先載入初始化器,VendorRoot通過如下方式載入:

    Ruby代碼 ?
  • class?VendorBoot?<?Boot??
  • ??def?load_initializer??
  • ????require?"#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"??
  • ??end??
  • end??
  • GemRoot通過如下方式載入:

    Ruby代碼 ?
  • 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,其中包括了此代碼文件中最重要的兩個類:Configuration和Initializer。從類名我們就可以很清晰的了解到,Initializer類完成Rails的初始化工作,當然這個過程需要各種各樣的配置,參數,這些則由Configuration提供。那么首先來看看Configuration提供了Rails所需的哪些配置參數,詳見下表:

    配置名(accessor名)具體描述
    frameworks會被載入的Rails框架組件列表,會包括action_controller,action_view等
    load_paths附加的load路徑列表,app/controller;app/models等Rails項目下的目錄
    load_once_pathsRails只會load一次的目錄,似乎目前版本的Rails未用到這個參數
    log_path日志文件的路徑,根據目前的環境(development,test,production)決定
    log_levelRails日志器的日志級別(info,debug)
    view_pathview的目錄路徑,默認路徑是app/view了
    controller_pathscontroller的目錄路徑,默認路徑是app/controller
    cache_classes是否對類進行緩存。目前未使用(一直是false)
    whiny_nilstrue/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)),十分簡單:

    Ruby代碼 ?
  • def?self.run(command?=?:process,?configuration?=?Configuration.new)??
  • ??yield?configuration?if?block_given???
  • ??initializer?=?new?configuration??
  • ??initializer.send(command)??
  • ??initializer??
  • end??
  • 現在我們姑且不管block(boot.rb調用他的時候確實也沒有關聯一個block),接下來的工作是生成一個新的Configuration對象,并賦給Initializer的構造函數(然后由Initializer對象保存該配置對象),然后執行initializer上的command方法,默認情況是執行process方法,這里通過boot.rb的調用,將執行set_load_path方法。在這里值得注意的是,新生成的Configuration對象的所有配置參數都是默認值,例如:frameworks參數通過如下方法得到默認值:

    Ruby代碼 ?
  • def?default_frameworks??
  • ??[?:active_record,?:action_controller,?:action_view,?:action_mailer,?:active_resource?]??
  • end??
  • controller_path參數通過如下方法得到默認值:

    ?

    Ruby代碼 ?
  • def?default_controller_paths??
  • ??paths?=?[File.join(root_path,?'app',?'controllers')]??
  • ??paths.concat?builtin_directories??
  • ??paths??
  • end??
  • 其實,所有的這些配置都不是定死的,我們可以在enviroment.rb中重新定義他們,象下面這樣:

    Ruby代碼 ?
  • 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:

    Ruby代碼 ?
  • require?File.dirname(__FILE__)?+?'/../config/boot'??
  • require?'commands/server'??
  • 該執行第二句了,下面輪到server.rb出場了。

    ? server.rb

    源代碼路徑:gems/rails-2.0.2/lib/commands/server.rb
    ? server.rb主要完成兩個功能:1.加載active_support;2.加載web服務器。
    ? 加載active_support十分簡單,只是通過源代碼開始的第一句:

    Ruby代碼 ?
  • require?'active_support'??
  • 加載web服務器相比復雜一些。首先,Rails會試圖加載FastCGI,然后會試圖加載mongrel,如下代碼所示:

    Ruby代碼 ?
  • 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)來決定使用哪種服務器。當然,本文前面提到了將使用WEBRick作為web服務器,這里最終加載的服務器當然是webrick。server.rb的最后一句代碼:?

    Ruby代碼 ?
  • 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.執行DispatchServlet(在webrick_server.rb中定義)的類方法dispatch。整個過程都是順序完成的,所以,示意的源代碼可以如下所示:

    Ruby代碼 ?
  • 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啟動所執行的最后一個源代碼文件。我前面提到了一點,此源代碼文件中定義了DispatchServlet,這是一個自定義的dispatch servlet,用于將瀏覽器的請求dispatch到相應的controller,action上。因為這里我只打算介紹Rails的啟動,所以,我們只用關注如下的代碼即可:

    Ruby代碼 ?
  • 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,并且,DispatchServlet類中還有一些重要的方法,我們暫時可以將他們擱在一旁。以后進一步分析Rails的時候再講解。? OK。至此,Rails就正式上馬了,web服務器也啟動起來了,接下來的事情,當然是等著web服務器將request轉發給Rails進行處理了,按照國際慣例,這當然是下文分解的事了~?


    轉載至:http://www.iteye.com/topic/170683

    總結

    以上是生活随笔為你收集整理的Ruby On Rails-2.0.2源代码分析(1)-Rails的启动的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。