Ruby on rails 項目啓動流程

衆所周知,我們可以通過rails s 這個命令來啓動一個rails 項目,但是這條命令都幹了哪些事呢?抽時間研究了下,同時感謝tomwang1013的博客。當我們輸入rails s 這個命令的時候,項目會加載項目bin/rails.rb 這個文件
#!/usr/bin/env ruby
APP_PATH = File.expand_path('../../config/application', __FILE__)
require_relative '../config/boot'
require 'rails/commands'

通過代碼我們可以看到這個文件中定義了一個APP_PATH 即我們的項目文件:config/application.rb,並require了config/boot,boot文件主要是做了bundle的初始化。
然後,我們可以看到這個時候rails/commands(railties-3.2.3/lib/rails/commands.rb)文件被load進來,由於我們傳入的command參數爲s,也就是server,然後我們看看commands的這個文件的源碼對應的部分:

when 'server'                                                                                         
  # Change to the application's path if there is no config.ru file in current dir.                    
  # This allows us to run script/rails server from other directories, but still get                   
  # the main config.ru and properly set the tmp directory.                                            
  Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exists?(File.expand_path("config.ru"))  

  require 'rails/commands/server'                                                                     
  Rails::Server.new.tap { |server|                                                                    
    # We need to require application after the server sets environment,                               
    # otherwise the --environment option given to the server won't propagate.                         
    require APP_PATH                                                                                  
    Dir.chdir(Rails.application.root)                                                                 
    server.start                                                                                      
  }    

在server 這個方法中我們通過server.start這行代碼可以看出最終調用了start這個方法,然後查看下start 這個方法。同時這裏面也打印了我們熟悉的控制檯信息

def start                                                                          
  url = "#{options[:SSLEnable] ? 'https' : 'http'}://#{options[:Host]}:#{options[:Port]}"  
  puts "=> Booting #{ActiveSupport::Inflector.demodulize(server)}"                 
  puts "=> Rails #{Rails.version} application starting in #{Rails.env} on #{url}"  
  puts "=> Call with -d to detach" unless options[:daemonize]  
  trap(:INT) { exit }  
  puts "=> Ctrl-C to shutdown server" unless options[:daemonize]  
  #Create required tmp directories if not found                                    
  %w(cache pids sessions sockets).each do |dir_to_make|                            
    FileUtils.mkdir_p(Rails.root.join('tmp', dir_to_make))                         
  end                                                                              

  puts 'server start ---'  
  super  
ensure  
  # The '-h' option calls exit before @options is set.                             
  # If we call 'options' with it unset, we get double help banners.                
  puts 'Exiting' unless @options && options[:daemonize]                            
end   

這個start 這個方法最終會執行super 這個,super 會調用Rack::Server#start方法:代碼

def start &blk  
  if options[:warn]  
    $-w = true                                                     
  end                                                              

  if includes = options[:include]  
    $LOAD_PATH.unshift(*includes)                                  
  end  

  if library = options[:require]                                   
    require library  
  end  

  if options[:debug]  
    $DEBUG = true                                                  
    require 'pp'  
    p options[:server]                                             
    pp wrapped_app  
    pp app  
  end  

  # Touch the wrapped app, so that the config.ru is loaded before  
  # daemonization (i.e. before chdir, etc).                        
  wrapped_app  

  daemonize_app if options[:daemonize]                             
  write_pid if options[:pid]  

  trap(:INT) do  
    if server.respond_to?(:shutdown)                               
      server.shutdown  
    else                                                           
      exit  
    end                                                            
  end  

  server.run wrapped_app, options, &blk  
end  

代碼執行到server.run wrapped_app 這行代碼。wrapped_app方法最終又會調用Rack::Server#app

def app  
  @app ||= begin                                                                
    if !::File.exist? options[:config]                                          
      abort "configuration #{options[:config]} not found"                       
    end  

    app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)  
    self.options.merge! options  
    app  
  end  
end     

最終app 這個方法會加載項目config 目錄下的environment.rb這個文件如:

# Load the Rails application.
require File.expand_path('../application', __FILE__)
require 'whenever'


module ProductConfig
  DYNAMIC_FIELDS = Hash.new
end

module RestConfig
  PRODUCT_SERVER = ENV["PHOTO_HOST"] || 'http://localhost:3001/'

  #CUSTOMER_SERVER = ENV["CUSTOMER_HOST"] || 'http://localhost:3001/'
  CUSTOMER_SERVER = ENV["CUSTOMER_HOST"] || 'http://localhost:3001/'

  OA_SERVER = 'http://localhost:3001/'

  #ELEPHANT_HOST = ENV["ELEPHANT_HOST"] || 'http://www.jiuyunda.net:90/'
  ELEPHANT_HOST = ENV["ELEPHANT_HOST"] || 'http://localhost:3001/'

  JXC_HOST = ENV["JXC_HOST"] || 'http://localhost:3001/'

  SETTLE_HOST = ENV["SETTLE_HOST"] || 'http://localhost:3001/'

end

# Initialize the Rails application.
Rails.application.initialize!

Rails.application.initialize!這行代碼我們可以看出
項目的初始化完成。這個時候我們代碼就回到Rack::Server#start方法的最後一行 server.run wrapped_app, options, &blk 由於我們沒有設定任何參數。通過代碼

def server                                                                         
  @_server ||= Rack::Handler.get(options[:server]) || Rack::Handler.default(options)  
end      
def self.default(options = {})          
  # Guess.                              
  if ENV.include?("PHP_FCGI_CHILDREN")  
    # We already speak FastCGI          
    options.delete :File                
    options.delete :Port                

    Rack::Handler::FastCGI              
  elsif ENV.include?("REQUEST_METHOD")  
    Rack::Handler::CGI                  
  else                                  
    begin                               
      Rack::Handler::Thin               
    rescue LoadError                    
      Rack::Handler::WEBrick            
    end                                 
  end                                   
end            

我們可以看到rack 爲我們選定了默認的server.一般來說是WEBrick .然後WEBrick啓動,打印如下信息

INFO  WEBrick 1.3.1  
INFO  ruby 1.9.3 
INFO  WEBrick::HTTPServer#start: pid=28371 port=3000 

如果安裝了其他application server的話打印的信息可能會不同如

Booting Puma
=> Rails 4.2.4 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
"assets end:false"
Puma starting in single mode...
* Version 3.4.0 (ruby 2.3.0-p0), codename: Owl Bowl Brawl
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://localhost:3000

至此項目的啓動已完成。

發佈了43 篇原創文章 · 獲贊 20 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章