def start
print_boot_information
trap(:INT) { exit }
create_tmp_directories
setup_dev_caching
log_to_stdout if options[:log_stdout]
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
执行完rails start的内容之后会执行::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
check_pid! if options[:pid]
# 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
这部分在解读rackup源码的时候已经了解过这里就不再次说明了,其最后执行的便是config.ru的内容了:
# This file is used by Rack-based servers to start the application.
require_relative 'config/environment'
run Rails.application
首先,我们看一下 environment的内容:
# Load the Rails application.
require_relative 'application'
# Initialize the Rails application.
Rails.application.initialize!
application 早在server_command 的perform方法里require过了 这里不会重复加载,然后是Rails.application.initialize!方法。
# lib/rails/application
def initialize!(group=:default) #:nodoc:
raise "Application has been already initialized." if @initialized
run_initializers(group, self)
@initialized = true
self
end
# lib/rails/initializable
def run_initializers(group = :default, *args)
return if instance_variable_defined?(:@ran)
initializers.tsort_each do |initializer|
initializer.run(*args) if initializer.belongs_to?(group)
end
@ran = true
end
# /lib/rails/application.rb
def initializers #:nodoc:
Bootstrap.initializers_for(self) +
railties_initializers(super) +
Finisher.initializers_for(self)
end
# /lib/rails/application.rb
def railties_initializers(current) #:nodoc:
initializers = []
ordered_railties.reverse.flatten.each do |r|
if r == self
initializers += current
else
initializers += r.initializers
end
end
initializers
end
def ordered_railties #:nodoc:
@ordered_railties ||= begin
order = config.railties_order.map do |railtie|
if railtie == :main_app
self
elsif railtie.respond_to?(:instance)
railtie.instance
else
railtie
end
end
all = (railties - order)
all.push(self) unless (all + order).include?(self)
order.push(:all) unless order.include?(:all)
index = order.index(:all)
order[index] = all
order
end
end
我们先看ordered_railties在每个类继承Railte 或者 Engine时都会往Railtie的subclass里插入该类的常量:
# lib/rails/railtie.rb
def inherited(base)
unless base.abstract_railtie?
subclasses << base
end
end
# lib/rails/engine.rb
def railties
@railties ||= Railties.new
end
# lib/rails/engine/railties.rb
def initialize
@_all ||= ::Rails::Railtie.subclasses.map(&:instance) +
::Rails::Engine.subclasses.map(&:instance)
end
然后我们最后拿到的数组是 Railties.new出来的也就是所有继承了Railtie和Engine的对象的示例,回到application的initializers方法让这些示例全都执行initializers_for。
def initializers_chain
initializers = Collection.new
ancestors.reverse_each do |klass|
next unless klass.respond_to?(:initializers)
initializers = initializers + klass.initializers
end
initializers
end
def initializers_for(binding)
Collection.new(initializers_chain.map { |i| i.bind(binding) })
end
def initializer(name, opts = {}, &blk)
raise ArgumentError, "A block must be passed when defining an initializer" unless blk
opts[:after] ||= initializers.last.name unless initializers.empty? || initializers.find { |i| i.name == opts[:before] }
initializers << Initializer.new(name, nil, opts, &blk)
end
这里就是找到这些实例里所有的祖先里有initializers方法的。initializer方法主要是new一个Initialize对象然后push到initializers数组里,最后通过bind方法设置好每个initialize的context属性。
def run_initializers(group = :default, *args)
return if instance_variable_defined?(:@ran)
initializers.tsort_each do |initializer|
initializer.run(*args) if initializer.belongs_to?(group)
end
@ran = true
end
然后将这些对象统统执行run方法.
def run(*args)
@context.instance_exec(*args, &block)
end
run方法也就是对每个相应的对象执行initialize的block.
网友评论