眾所周知,我們可以通過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 }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
在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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
這個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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
代碼執行到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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
最終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!
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
我們可以看到rack 為我們選定了默認的server.一般來說是WEBrick .然后WEBrick啟動,打印如下信息
INFO WEBrick 1.3.1 INFO ruby 1.9.3 INFO WEBrick::HTTPServer#start: pid=28371 port=3000
- 1
- 2
- 3
如果安裝了其他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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
至此項目的啟動已完成。
