论坛首页 编程语言技术论坛

Rails启动过程

浏览 3443 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-02-01  
Rails启动过程

在每个应用程序的/public目录下,都含有:dispatch.cgi、dispatch.fcgi、dispatch.rb 3个分发文件。系统会根据我们的配置执行其中相应的文件,调用不同的处理方式(CGI,FastCGI或是Ruby方式),同时该文件会加载整个rails环境。3个文件中的内容基本一样,仅对其中一个分发文件进行探讨!

这几个分发文件,首先通过如下代码读入/config目录下的environment.rb文件。
代码:
require File.dirname(_FIFE_)+"/../config/enviroment" unless defined?(RAILS_ROOT)


而在enviroment.rb文件中,一般可以查看Rails版本。
代码:
RAILS_GEM_VERSION = '2.0.2' # unless defined? RAILS_GEM_VERSION


由于没有定RAILS_ROOT会继续调用/config目录下的boot.rb文件:
代码:
require File.join(File.dirname(__FILE__), 'boot')


查看root.rb文件,它做了这样几件事情。一:设置环境变量
代码:
RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)


二:boot.rb接下来会检查是否存在#{RAILS_ROOT}/vendor/rails目录。因为rails应用程序的运行环境和版本关系比较大。如果存在boot.rb会启动该目录下的Rails初始化程序。否则boot.rb会加载rubygems并搜索environment.rb文件。如果不存在常量,boot.rb会尝试初始化系统最近安装的rails版本。

三:定义了正确的初始化程序路径。boot.rb会调用Rails模块下的Initializer类中的类方法run。
代码:Rails模块
# Don't change this file!
# Configure your app in config/environment.rb and config/environments/*.rb

RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)

module Rails
  class << self
    def boot!
      unless booted?
        preinitialize
        pick_boot.run
      end
    end

    def booted?
      defined? Rails::Initializer
    end

    def pick_boot
      (vendor_rails? ? VendorBoot : GemBoot).new
    end

    def vendor_rails?
      File.exist?("#{RAILS_ROOT}/vendor/rails")
    end

    # FIXME : Ruby 1.9
    def preinitialize
      load(preinitializer_path) if File.exists?(preinitializer_path)
    end

    def preinitializer_path
      "#{RAILS_ROOT}/config/preinitializer.rb"
    end
  end

  class Boot
    def run
      load_initializer
      Rails::Initializer.run(:set_load_path)
    end
  end

  class VendorBoot < Boot
    def load_initializer
      require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
    end
  end

  class GemBoot < Boot
    def load_initializer
      self.class.load_rubygems
      load_rails_gem
      require 'initializer'
    end

    def load_rails_gem
      if version = self.class.gem_version
        gem 'rails', version
      else
        gem 'rails'
      end
    rescue Gem::LoadError => load_error
      $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
      exit 1
    end

    class << self
      def rubygems_version
        Gem::RubyGemsVersion if defined? Gem::RubyGemsVersion
      end

      def gem_version
        if defined? RAILS_GEM_VERSION
          RAILS_GEM_VERSION
        elsif ENV.include?('RAILS_GEM_VERSION')
          ENV['RAILS_GEM_VERSION']
        else
          parse_gem_version(read_environment_rb)
        end
      end

      def load_rubygems
        require 'rubygems'

        unless rubygems_version >= '0.9.4'
          $stderr.puts %(Rails requires RubyGems >= 0.9.4 (you have #{rubygems_version}). Please `gem update --system` and try again.)
          exit 1
        end

      rescue LoadError
        $stderr.puts %(Rails requires RubyGems >= 0.9.4. Please install RubyGems and try again: http://rubygems.rubyforge.org)
        exit 1
      end

      def parse_gem_version(text)
        $1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/
      end

      private
        def read_environment_rb
          File.read("#{RAILS_ROOT}/config/environment.rb")
        end
    end
  end
end

# All that for this:
Rails.boot!

模块有两个类:Initializer和Configuration。
Initializer类负责处理Rails的配置选项,并设置Rails的加载文件的路径。
Configuration维护Rails环境的配置参数。

Initializer 的run方法
 def self.run(command = :process, configuration = Configuration.new)
      yield configuration if block_given?
      initializer = new configuration
      initializer.send(command)
      initializer
 end


Configuration类会加载应用程序中相关的目录,并加载相关的文件
如:
def default_load_paths
        paths = []

        # Add the old mock paths only if the directories exists
        paths.concat(Dir["#{root_path}/test/mocks/#{environment}"]) if File.exists?("#{root_path}/test/mocks/#{environment}")

        # Add the app's controller directory
        paths.concat(Dir["#{root_path}/app/controllers/"])

        # Then components subdirectories.
        paths.concat(Dir["#{root_path}/components/[_a-z]*"])

        # Followed by the standard includes.
        paths.concat %w(
          app
          app/models
          app/controllers
          app/helpers
          app/services
          components
          config
          lib
          vendor
        ).map { |dir| "#{root_path}/#{dir}" }.select { |dir| File.directory?(dir) }

        paths.concat builtin_directories
      end

你也可以做相应的修改。

初始化过程结束返回到enviroment.rb文件。
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics