`
fantaxy025025
  • 浏览: 1328702 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类

Rails源码阅读(三)Rails::Initializer

阅读更多

 

启动的落脚点

不论启动console还是启动server,最终都需要加载rails环境,这个落脚点在environment.rb中的Rails::Initializer.run 

Rails::Initializer.run do |config|

。。。

end
 

启动前的配置Configuration

加载rails环境,需要的配置是比较多的,例如:启动的root_path,启动时要加载的frameworks,加载的路径,插件的位置,数据库的配置,log的配置,i18n的配置等等。这些都在Configuration类中配置。

  # The Configuration class holds all the parameters for the Initializer and
  # ships with defaults that suites most Rails applications. But it's possible
  # to overwrite everything. Usually, you'll create an Configuration file
  # implicitly through the block running on the Initializer, but it's also
  # possible to create the Configuration instance in advance and pass it in
  # like this:
  #
  #   config = Rails::Configuration.new
  #   Rails::Initializer.run(:process, config)
  class Configuration

  。。。

  end
  

启动前再配置

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

# 在上面environment的启动中,configuration参数使用了默认的配置值Configuration.new

# 同时看到了,yield configuration if block_given?会把configuration传递给block,这样可以在启动时配置config的一些参数,而不用修改configuration类(这样也是可以的)

# 再回到上面的落脚点的代码,看到了这里的参数config原来就是configuration,也就是说想知道怎么配置config,需要了解configuration的内容和api。

好了,好多人跟我一样,困惑许久的config是什么,如何配置的问题,现在解决了。

 

启动1

继续往下看,这里有一句:initializer = new configuration

这种写法让我这种多年的javaer很反感,明明这么写更好理解么:initializer = Initializer.new(configuration)

javaer理解中的new是这样的:User user = new User(...)

initializer.send(command)

 

 

 

这里调用了实例方法command,根据command = :process知道,调用的方法是process方法。就是这里进入启动环节。

 

启动2 可以说,直接看这里就是rails的启动过程

    # Sequentially step through all of the available initialization routines,
    # in order (view execution order in source).
    def process

。。。

    end
 

 

启动3 仔细看看启动都做了些什么

check_ruby_version

检查版本,不对的话会报异常,详细略

 

install_gem_spec_stubs

看看stub的字样,表示这里的install其实是个“伪”install,目的是给plugin使用的。

说明:

  This allows Gem plugins to depend on Rails even when the Gem version of Rails shouldn't be loaded

代码:

  install_gem_spec_stubsGem.loaded_specs[stub] = Gem::Specification.new 。。。

 

set_load_path

配置$LOAD_PATH

说明:Set the $LOAD_PATH based on the value of Configuration

 

add_gem_load_paths

使用的对象为@gems

  来源:configuration中的@gems << Rails::GemDependency.new(name, options)

调用了Rails::GemDependency的add_load_paths方法,这个方法内容主要使用了gem ‘some_gem' 'edition_n'

 

require_frameworks

依次执行 require ‘activesupport’ 等, 简而言之,这里才真正的require了,这里之后才真正可以使用这些framework

这里之后的方法,基本可以说能使用rails的这些组件了

 

set_autoload_paths

字面意义

把configuration里面的auto_load_paths 赋值给了ActiveSupport::Dependencies

关于ActiveSupport::Dependencies,以后再看看,暂不清楚内部原理

 

add_plugin_load_paths

主要由plugin_loader来

 

load_environment

这里会调用到所在环境(production,development,test)对应的rb文件

    def environment_path
      "#{root_path}/config/environments/#{environment}.rb"
    end

 并且把常量设置在了Object中(好处呢,首先是在任何地方都可以直接用了吧)

        (self.class.constants - constants).each do |const|
          Object.const_set(const, self.class.const_get(const))
        end

 我在我的环境里看了看,果然常量增加了不少

 

#irb初始情况下:
irb(main):011:0>  Object.constants.size
=> 101

#我的rails环境
?> Object.constants.size
=> 429

最后再重复一个问题,程序运行到这里,能不能使用rails的插件呢?

可以!例如active_support

但不全部,例如有些组建还要进行初始化操作,像active_record的数据库建立等

 

preload_frameworks

作用是为了Passenger/JRuby等使用

主要操作是显式调用各个组件的 framework.load_all! 方法

我看了看几个组件,居然是都有load_all!这个方法

module ActiveSupport
  def self.load_all!
    [Dependencies, Deprecation, Gzip, MessageVerifier, Multibyte, SecureRandom, TimeWithZone]
  end
。。。
end

module ActiveRecord
  # TODO: Review explicit loads to see if they will automatically be handled by the initilizer.
  def self.load_all!
    [Base, DynamicFinderMatch, ConnectionAdapters::AbstractAdapter]
  end
。。。
end
 

initialize_encoding

这个类做了什么呢,怎么设置编码的呢?

Ruby1.8设置$KCODE

Ruby1.9默认是utf-8了

# For Ruby 1.8, this initialization sets $KCODE to 'u' to enable the
    # multibyte safe operations. Plugin authors supporting other encodings
    # should override this behaviour and set the relevant +default_charset+
    # on ActionController::Base.
    #
    # For Ruby 1.9, this does nothing. Specify the default encoding in the Ruby
    # shebang line if you don't want UTF-8.
    def initialize_encoding
      $KCODE='u' if RUBY_VERSION < '1.9'
    end
 

 

initialize_database

这里才建立数据库连接了!!

也就是说从这里开始才能使用ActiveRecord来查询数据库

 

initialize_cache

放置缓存,页面缓存,块缓存等的地方

*1 如果默认位置: "#{root_path}/tmp/cache/"路径不存在则用内存了

    def default_cache_store
        if File.exist?("#{root_path}/tmp/cache/")
          [ :file_store, "#{root_path}/tmp/cache/" ]
        else
          :memory_store
        end
      end

*2 这里从config得到了cache_store的类型,并初始化了一个cache_store

     这里居然用了silence_wornings,很明显不让你随意设置咯

silence_warnings { Object.const_set "RAILS_CACHE", ActiveSupport::Cache.lookup_store(configuration.cache_store) }

 

*3 cache_store的结果是返回一个cache_store对象,并不是一个配置

    # Creates a new CacheStore object according to the given options.
    #
    # If no arguments are passed to this method, then a new
    # ActiveSupport::Cache::MemoryStore object will be returned.
    #
    # If you pass a Symbol as the first argument, then a corresponding cache
    # store class under the ActiveSupport::Cache namespace will be created.
    # For example:
    #
    #   ActiveSupport::Cache.lookup_store(:memory_store)
 

initialize_framework_caches

这里只是简单的使用了上面设置的cache

 

    def initialize_framework_caches
      if configuration.frameworks.include?(:action_controller)
        ActionController::Base.cache_store ||= RAILS_CACHE
      end
    end

 

 

initialize_logger

initialize_framework_logging

设置logger,如果config里面设置了logger,则基本跳过了。

*1 logger用的哪个类呢

     logger = ActiveSupport::BufferedLogger.new(configuration.log_path)

*2 production的特殊配置

          if configuration.environment == "production"
            logger.auto_flushing = false
          end  

 

*3 logger leve 这里是默认的,可以在config里配置新的

 

      def default_log_path
        File.join(root_path, 'log', "#{environment}.log")
      end

      def default_log_level
        environment == 'production' ? :info : :debug
      end

*4 可以给不同的组建单独配置其logger

     这个在ide测试的时候有用,比如在test里,可以把active_record的log打入ide,便于调试

    def initialize_framework_logging
      for framework in ([ :active_record, :action_controller, :action_mailer ] & configuration.frameworks)
        framework.to_s.camelize.constantize.const_get("Base").logger ||= Rails.logger
      end

      ActiveSupport::Dependencies.logger ||= Rails.logger
      Rails.cache.logger ||= Rails.logger
    end
 

initialize_dependency_mechanism

代理了类加载的机制,从而可以配置在开发环境和product环境中,加载类可以用不同的机制

 

    # Sets the dependency loading mechanism based on the value of
    # Configuration#cache_classes.
    def initialize_dependency_mechanism
      ActiveSupport::Dependencies.mechanism = configuration.cache_classes ? :require : :load
    end

 

 ActiveSupport::Dependencies这个类显然有很重要的地位,比如你看看大部分你用到的类都没有使用require ‘xxx’方法!!

 

 

initialize_whiny_nils

不用多说了,就是whiny_nil 的改写

 

initialize_time_zone

这个意图也清楚。但下面的代码没有弄明白具体含义,待补充吧。

设置adtive_record可以理解,但是最后一行,么意思呢。。。???

 

        if configuration.frameworks.include?(:active_record)
          ActiveRecord::Base.time_zone_aware_attributes = true
          ActiveRecord::Base.default_timezone = :utc
        end

 

 

initialize_i18n

    def initialize_i18n
      configuration.i18n.each do |setting, value|
        if setting == :load_path
          I18n.load_path += value
        else
          I18n.send("#{setting}=", value)
        end
      end
    end

  #1 可见,如果配置了load_path则I18n类中加入这个路径;否则,认为是配置i18n的属性

 

  #2 在config中可以这么配置:

  # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
  # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
  #   config.i18n.default_locale = :cn
  config.i18n.default_locale = 'zh_cn'

  config.i18n.load_path += Dir[
    Rails.root.join('config', 'locales', 'user', '*.{rb,yml}'),
    Rails.root.join('config', 'locales', 'message', '*.{rb,yml}')
  ]

  #3 最后,必须要说的是,这里用到了重写的ActiveSupport的类:

class Rails::OrderedOptions < Array                。。。              end
 

initialize_framework_settings 

    # Initializes framework-specific settings for each of the loaded frameworks
    # (Configuration#frameworks). The available settings map to the accessors
    # on each of the corresponding Base classes.
    def initialize_framework_settings
      configuration.frameworks.each do |framework|
        base_class = framework.to_s.camelize.constantize.const_get("Base")

        configuration.send(framework).each do |setting, value|
          base_class.send("#{setting}=", value)
        end
      end
      configuration.active_support.each do |setting, value|
        ActiveSupport.send("#{setting}=", value)
      end
    end

 根据下面的注释,可以知道:

*1 某个framefork都有哪些项目可以配置?例如active_record

     参考framefork的Base类

*2 配置的地方?

     还是上面提到的,在environment的中配置

*3 配置怎么写?

# Show full error reports and disable caching
config.action_controller.consider_all_requests_local = true
config.action_view.debug_rjs                         = true

 #June: we can test cache here(comment 2 lines && uncomment 3 lines after)
config.action_controller.perform_caching             = false
config.action_view.cache_template_loading            = false

 *4 为什么可以这么写?

    还是需要明白Rails::OrderedOptions也就是ActiveSupport::OrderedOptions的用法

 *5 active_support应该没有base类咯,看出来了么

 

initialize_framework_views

基本上可以同上。

 

initialize_metal

请看metal的用法吧

 

add_support_load_paths

空方法???

 

check_for_unbuilt_gems

这里可以安装config中配置到gem

 

load_gems

使用config中的gem

 

 

      # pick up any gems that plugins depend on

      add_gem_load_paths

      load_gems

      check_gem_dependencies

 

 

load_application_initializers

config/initializers目录下面的文件会在rails server启动最后顺序执行,顺序为文件名排序,所以有依赖关系的话,就得提前安排一下,例如db:migrate那样加入时间戳么。总之在这里安排顺序就是个很懒的设计了。

看看源码:

    def load_application_initializers
      if gems_dependencies_loaded
        Dir["#{configuration.root_path}/config/initializers/**/*.rb"].sort.each do |initializer|
          load(initializer)
        end
      end
    end

 

方法没有叫做after_initialize,因为这里安排的仍然是app启动的一项

 

after_initialize 

这里才是启动之后的操作,回调。

例如这里可以给分页的插件中文话。

 

initialize_database_middleware

这里会检查配置的session_store情况,如果配置了下面的目标内容,就会用数据库来存session了

ActionController::Base.session_store.name == 'ActiveRecord::SessionStore' (去配置config)

 

prepare_dispatcher

# Prepare dispatcher callbacks and run 'prepare' callbacks

看样子好像是加载了dispatcher并define_dispatcher_callbacks(configuration.cache_classes)

这里设置了@@cache_classes = cache_classes

作用:

# In the development environment your application's code is reloaded on
# every request.  This slows down response time but is perfect for development
# since you don't have to restart the webserver when you make code changes.
config.cache_classes = false

 

initialize_routing

代码:

    # If Action Controller is not one of the loaded frameworks (Configuration#frameworks)
    # this does nothing. Otherwise, it loads the routing definitions and sets up
    # loading module used to lazily load controllers (Configuration#controller_paths).
    def initialize_routing
      return unless configuration.frameworks.include?(:action_controller)

      ActionController::Routing.controller_paths += configuration.controller_paths
      #### Me added this line ###
      ActionController::Routing::Routes.add_configuration_file(File.join("/home/lijg/workrubygit/t8", 'config', 'routes2.rb'))
      ActionController::Routing::Routes.add_configuration_file(configuration.routes_configuration_file)
      ActionController::Routing::Routes.reload!
    end

 

这里的作用:

*1 知晓controller的位置,等需要的时候去得到这个类

*2 知晓routes文件的位置,load it

     这里的文件,可以是多个的,内部是可以处理的

configuration_files.each { |config| load(config) }

*3 reload!

      def load!
        Routing.use_controllers!(nil) # Clear the controller cache so we may discover new ones
        clear!
        load_routes!
      end

      # reload! will always force a reload whereas load checks the timestamp first
      alias reload! load!

*4 加入一些自己想要的controller

有时候想测试一个需求(不用git哦),想加入一些自己的routes和mvc看看情况,这个时候就可以用这个了。

这里仅仅是个小实验,所以简单修改了下源码。

*5 注意这里的顺序,路由加入的时候,优先加入的会先匹配。这样我的测试路由优先加入比较好~

 

load_observers

这个是给active_record使用的ActiveRecord::Base.instantiate_observers

看看里面的代码:

"#{observer} must be a lowercase, underscored class name (or an instance of the class itself) responding to the instance method. Example: Person.observers = :big_brother # calls BigBrother.instance"

 

load_view_paths

这两个组件在用view的路径

ActionController::Base.view_paths.load!

ActionMailer::Base.view_paths.load!

 

load_application_classes

*1 如果设置了某些自动加载的路径,这时会加载

     例如在env中这样的设置:config.load_paths <<  "#{RAILS_ROOT}/app/middleware"

*2 加载了这个目录以及子目录下的所有.rb文件

     Dir.glob("#{load_path}/**/*.rb"

*3 这里加载方式:require_dependency

 

    # Eager load application classes
    def load_application_classes
      return if $rails_rake_task
      if configuration.cache_classes
        configuration.eager_load_paths.each do |load_path|
          matcher = /\A#{Regexp.escape(load_path)}(.*)\.rb\Z/
          Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
            require_dependency file.sub(matcher, '\1')
          end
        end
      end
    end 

写到这里,我想需要把rails2的自动加载路径打印出来看看

 

--------------------------------------------------

/home/lijg/workrubygit/t8/app/controllers/

/home/lijg/workrubygit/t8/app

/home/lijg/workrubygit/t8/app/models

/home/lijg/workrubygit/t8/app/controllers

/home/lijg/workrubygit/t8/app/helpers

/home/lijg/workrubygit/t8/lib #看见了,这个在rails2是自动加入的,但rails3好像不同了

/home/lijg/workrubygit/t8/vendor

/home/lijg/workrubygit/t8/config/../vendor/rails/railties/lib/../builtin/rails_info/

/home/lijg/workrubygit/t8/app/middleware #这个是我自己设置的

--------------------------------------------------

 

disable_dependency_loading

用到了这个:ActiveSupport::Dependencies.unhook!

 

本篇完毕

作业:需要再仔细看看的

require_dependency

auto_load

ActiveSupport::Dependencies

 

----本篇完毕---- -----EOF---- ----THE END----

+

o

o

o

 

 

 

 

 

 

 

分享到:
评论
2 楼 fantaxy025025 2011-10-14  
orcl_zhang 写道
这个太简单了吧。。。

sorry阿,这里暂时占了个位置,还是没有那么多时间一下子写完了~待续~
1 楼 orcl_zhang 2011-10-14  
这个太简单了吧。。。

相关推荐

    白色大气风格的建筑商业网站模板下载.rar

    白色大气风格的建筑商业网站模板下载.rar

    面向对象编程语言Objective-C基础语法详解及应用

    内容概要:本文详细介绍了面向对象编程语言Objective-C的基础语法,包括其历史背景、特点、环境搭建、基本语法、面向对象编程、高级特性和实际应用。具体涵盖的内容包括Objective-C的历史发展、面向对象编程的核心特性、变量和数据类型、控制结构、函数、数组和字典的使用,以及类、对象、属性和方法的定义与使用。此外,还介绍了高级特性如协议和委托、类别和扩展、ARC、块和GCD。最后,通过示例项目展示了如何在Xcode中创建和调试Objective-C程序,以及如何使用Cocoa和Cocoa Touch框架。 适合人群:具备一定的编程基础,希望学习或深入了解Objective-C编程的开发人员。 使用场景及目标:适用于需要开发macOS和iOS应用的开发者,帮助他们掌握Objective-C的基本语法和高级特性,提高编程效率和代码质量。 其他说明:本文不仅提供了详细的理论讲解,还通过实际代码示例展示了如何在Xcode中创建和调试Objective-C项目,适合初级到中级水平的开发人员学习和参考。

    球馆预约系统ssm.zip

    本次开发的微信小程球馆预约系统,有管理员,用户两个角色。管理员功能有个人中心,用户管理,场地类型管理,球馆信息管理,球馆预约管理,系统管理。用户可以在微信小程序上面注册登录,查看球馆信息,对球馆进行预约操作。 开发本程序后台用到了SSM开发技术,微信端用的是uni-app技术。数据库采用关系数据库市场占有率最高的MySQL作为本程序使用的数据库,完全符合程序使用并且有丰富的拓展余地。 用户在微信小程序注册登录后可以看到首页,首页可以搜索球馆名称,也可以查看球馆资讯,下面是导航栏。 用户点击球馆信息可以进行预约,预约需要输入相关时间等信息。 我的里面可以修改个人信息,可以退出,还可以查看球馆预约信息和我的收藏信息。

    STM32F030单片机串口2发送接收.zip

    1、嵌入式物联网单片机项目开发例程,简单、方便、好用,节省开发时间。 2、代码使用KEIL 标准库开发,当前在STM32F030C8T6运行,如果是STM32F030其他型号芯片,依然适用,请自行更改KEIL芯片型号以及FLASH容量即可。 3、软件下载时,请注意keil选择项是jlink还是stlink。 4、有偿指导v:wulianjishu666; 5、如果接入其他传感器,请查看账号发布的其他资料。 6、单片机与模块的接线,在代码当中均有定义,请自行对照。 7、若硬件有差异,请根据自身情况调整代码,程序仅供参考学习。 8、代码有注释说明,请耐心阅读。 9、编译时请注意提示,请选择合适的编译器版本。

    廖鹏盛 - 时代进行曲.zip

    廖鹏盛 - 时代进行曲.zip

    白色大气风格的人体艺术摄影网站模板下载.zip

    白色大气风格的人体艺术摄影网站模板下载.zip

    白色大气风格的服装设计师模板下载.zip

    白色大气风格的服装设计师模板下载.zip

    白色大气风格的景观设计HTML网站模板.zip

    白色大气风格的景观设计HTML网站模板.zip

    (176226648)机器学习领域,基于TensorFlow与mnist数据集,实现手写数字识别,手写数字识别,机器学习学习首选项目

    优质的机器学习资源是当今科技领域的热点,其中TensorFlow作为谷歌公司的开源库,成为最受欢迎的深度学习框架之一,广泛应用于各类项目中。TensorFlow提供了丰富的功能和灵活性,使得开发者可以轻松构建和训练复杂的神经网络模型,处理图像、文本和其他类型的数据。由于其开源性质,拥有庞大的社区支持,用户可以放心使用,并从开源社区中获取宝贵的经验和资源。 mnist数据集是机器学习领域的经典数据集之一。它包含着大量的手写数字图像,供开发者用来训练和测试各种算法和模型。这个数据集的规模相对较小,因此对于绝大多数人来说,无论是数据的下载还是训练过程,都不会对电脑性能提出过高的要求。这使得mnist成为了理想的入门数据集,适合初学者探索和理解机器学习算法的基本原理。 结合Pygame与TensorFlow,你将能够为机器学习实验创建出图形化界面,以及实现交互式处理。Pygame是一款面向游戏和多媒体应用的Python库,但同样也可以用于数据可视化和图形化交互。利用Pygame,你可以展示训练过程中的图像输出、模型的预测结果等,增强对机器学习算法运行情况的直观认识。而且,Pygame的简单。内

    基于两种坐标系的超螺旋滑模观测器的永磁同步电机pmsm无位置(速度)传感器控制模型 支持 dq旋转坐标系和静止坐标系建立smo 引入二阶滑模超螺旋算法替代一阶滑模 dq坐标系引入锁相环PLL估计转速及

    基于两种坐标系的超螺旋滑模观测器的永磁同步电机pmsm无位置(速度)传感器控制模型 支持 dq旋转坐标系和静止坐标系建立smo 引入二阶滑模超螺旋算法替代一阶滑模 dq坐标系引入锁相环PLL估计转速及转子位置 有效削弱抖振 赠送超螺旋滑模搭建推导文档及相关参考资料 仿真模型

    汇编实验算数运算程序设计.docx

    汇编实验算数运算程序设计.docx

    小区监控视频监控方案.doc

    小区监控视频监控方案.doc

    白色大气风格的HTML商务模板下载.zip

    白色大气风格的HTML商务模板下载.zip

    白色大气风格响应式运动健身瑜伽企业网站模板.zip

    白色大气风格响应式运动健身瑜伽企业网站模板.zip

    单片机实验仿真设计报告

    单片机实验仿真设计报告

    白色大气风格的设计公司整站网站模板下载.zip

    白色大气风格的设计公司整站网站模板下载.zip

    白色大气风格的html商务模板.zip

    白色大气风格的html商务模板.zip

    白色大气风格的英文网站模板下载.zip

    白色大气风格的英文网站模板下载.zip

    白色大气风格的科研教育模板下载.zip

    白色大气风格的科研教育模板下载.zip

    stm32驱动摄像头ov7670源程序

    本摄像头ov7670驱动程序已经通过本人的验证可以正常运行,不同的stm32开发板只需要修改引脚即可使用

Global site tag (gtag.js) - Google Analytics