当你输入了rails server之后4

2019-11-05  本文已影响0人  will2yang
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.

上一篇下一篇

猜你喜欢

热点阅读