As i was working throught the rails 3 initialization process, i found that all the initializers defined in Rails::Engine(there are 10) were added to Rails::Application instance more than once. This means that these initializers would run many times. The following is the analysis: 1. Rails::Application#initializers:
def initializers #:nodoc:
Bootstrap.initializers_for(self) +
super +
Finisher.initializers_for(self)
end
It will call super(Rails::Engine) method which is defined as follows:
def initializers
initializers = []
ordered_railties.each do |r|
if r == self
initializers += super
else
initializers += r.initializers
end
end
initializers
end
We can see from Rails::Engine#initializers that every engine(class that inherited from Rails::Engine) will add Rails::Engine's initializers to that of it, including Rails::Application. But all the other engines are included in Rails::Application's ordered_railties, so their initializers are also added into that of Rails::Application. We can conclude that Rails::Engine's initializers are added many times to Rails::Application. We can see from the console info:
1.9.3p194 :002 > Rails.application.initializers.map(&:name).size
=> 119
1.9.3p194 :001 > Rails.application.initializers.map(&:name).uniq.size
=> 79
So every initializer in Rails::Engine is added 5 times to that of Rails::Application. I wonder why this happens? Is there some special reason?
An initializer has several other attributes except name: context, block, etc. So whenever an engine inherited from Rails::Engine, all of Rails::Engine's initializers are added to the child engine with a different context. That is, although there are duplicate initializers in Rails::Application with the same name, they are indeed differernt initializers which will run under different context:
def run(*args)
@context.instance_exec(*args, &block)
end