衆所周知,我們可以通過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
至此項目的啓動已完成。