美文网首页
当你输入了rails server之后4

当你输入了rails server之后4

作者: will2yang | 来源:发表于2019-11-05 20:34 被阅读0次
    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.

    相关文章

      网友评论

          本文标题:当你输入了rails server之后4

          本文链接:https://www.haomeiwen.com/subject/ataxhqtx.html