之前提到[链接]RabbitMQ会把启动过程分成若干阶段,按照依赖关系进行启动.rabbit_boot_step里面的requires 和 enables配置节是描述这种依赖关系的关键.require约定了该项目启动所依赖的前置条件,enables 表示当前项目启动之后可以启动什么;如果有多个项目enable一个项目(比如:external_infrastructure),要等这些项目都启动了external_infrastructure 才可以启动. 
 
   为什么要搞得那么复杂?一股脑调用启动不就行了?RabbitMQ启动过程中复杂的依赖关系,以及灵活扩展的要求,不可能随机顺序启动或者硬编码启动顺序.官方在GitHub上面举了一个例子:
 
   Boot steps can be separated into groups. A group of boot steps will enabled certain other group. For example routing_ready is actually enabled by many others boot steps, not just recovery. One of such steps is the empty_db_check that ensures that the Mnesia, Erlang's built-in distributed database, has the default data, like the default guest user for example. Also we can see that the recovery boot step also depends on empty_db_check so this logic takes care of running them in the right order that will satisfy the interdependencies they have.
 
 看一下上面所说的图形效果,这只是RabbitMQ整个启动过程的片段,[ 完整高清大图请点击这里 ]:
 

 
  整个启动过程,会被构造成一个有向无循环图,这里可以参考rabbit.erl的sort_boot_step方法
 
sort_boot_steps(UnsortedSteps) ->
    case rabbit_misc:build_acyclic_graph(fun vertices/2, fun edges/2,
                                         UnsortedSteps) of
        {ok, G} ->
            %% Use topological sort to find a consistent ordering (if
            %% there is one, otherwise fail).
            SortedSteps = lists:reverse(
                            [begin
                                 {StepName, Step} = digraph:vertex(G,
                                                                   StepName),
                                 Step
                             end || StepName <- digraph_utils:topsort(G)]),
            digraph:delete(G),
            %% Check that all mentioned {M,F,A} triples are exported.
            case [{StepName, {M,F,A}} ||
                     {StepName, Attributes} <- SortedSteps,
                     {mfa, {M,F,A}}         <- Attributes,
                     not erlang:function_exported(M, F, length(A))] of
                []               -> SortedSteps;
                MissingFunctions -> basic_boot_error(
                                      {missing_functions, MissingFunctions},
                                      "Boot step functions not exported: ~p~n",
                                      [MissingFunctions])
            end;
        {error, {vertex, duplicate, StepName}} ->
            basic_boot_error({duplicate_boot_step, StepName},
                             "Duplicate boot step name: ~w~n", [StepName]);
        {error, {edge, Reason, From, To}} ->
            basic_boot_error(
              {invalid_boot_step_dependency, From, To},
              "Could not add boot step dependency of ~w on ~w:~n~s",
              [To, From,
               case Reason of
                   {bad_vertex, V} ->
                       io_lib:format("Boot step not registered: ~w~n", [V]);
                   {bad_edge, [First | Rest]} ->
                       [io_lib:format("Cyclic dependency: ~w", [First]),
                        [io_lib:format(" depends on ~w", [Next]) ||
                            Next <- Rest],
                        io_lib:format(" depends on ~w~n", [First])]
               end])
    end.


DEMO


 看一个具体例子,RabbitMQ in Action 一书中rabbit_exchange_type_recent_history扩展.代码url: https://github.com/rabbitinaction/sourcecode 看看它的启动规格说明:

-rabbit_boot_step({?MODULE,
[{description, "exchange type x-recent-history"},
{mfa, {rabbit_registry, register,
[exchange, <<"x-recent-history">>, ?MODULE]}},
{requires, rabbit_registry},
{enables, kernel_ready}]}).

-rabbit_boot_step({rabbit_exchange_type_recent_history_mnesia,
[{description, "recent history exchange type: mnesia"},
{mfa, {?MODULE, setup_schema, []}},
{requires, database},
{enables, external_infrastructure}]}).

  参照上面的高清大图,可以看一下它会在什么位置完成上面两步操作.下面我们重新编译启动Rabbit,看下启动过程的输出,注意新增的部分:
 
Eshell V5.9  (abort with ^G)
(rabbit@nimbus)1>
+---+   +---+
|   |   |   |
|   |   |   |
|   |   |   |
|   +---+   +-------+
|                   |
| RabbitMQ  +---+   |
|           |   |   |
|   v3.0.0  +---+   |
|                   |
+-------------------+
AMQP 0-9-1 / 0-9 / 0-8
Copyright (C) 2007-2012 VMware, Inc.
Licensed under the MPL.  See http://www.rabbitmq.com/

node           : rabbit@nimbus
app descriptor : /data/rabbitmq-server-3.0.0/scripts/../ebin/rabbit.app
home dir       : /root
config file(s) : (none)
cookie hash    : qhI/+VnjqUPUYcXLZ2jZMQ==
log            : /var/log/rabbitmq/rabbit@nimbus.log
sasl log       : /var/log/rabbitmq/rabbit@nimbus-sasl.log
database dir   : /var/lib/rabbitmq/mnesia/rabbit@nimbus
erlang version : 5.9

-- rabbit boot start
starting file handle cache server                                     ...done
starting worker pool                                                  ...done
starting database                                                     ...done
starting database sync                                                ...done
starting codec correctness check                                      ...done
starting recent history exchange type: mnesia                         ...done  %%% 看这里 看这里
-- external infrastructure ready
starting statistics event manager                                     ...done
starting logging server                                               ...done
starting plugin registry                                              ...done
starting auth mechanism amqplain                                      ...done
starting auth mechanism cr-demo                                       ...done
starting auth mechanism plain                                         ...done
starting exchange type direct                                         ...done
starting exchange type fanout                                         ...done
starting exchange type headers                                        ...done
starting exchange type x-recent-history                               ...done   %%%%   看这里 看这里 
starting exchange type topic                                          ...done
-- kernel ready
starting node monitor                                                 ...done
starting cluster delegate                                             ...done
starting guid generator                                               ...done
starting alarm handler                                                ...done
starting memory monitor                                               ...done
-- core initialized
starting empty DB check                                               ...done
starting background garbage collection                                ...done
starting HA policy validation                                         ...done
starting policy parameters                                            ...done
starting exchange, queue and binding recovery                         ...done
starting mirror queue slave sup                                       ...done
starting adding mirrors to queues                                     ...done
-- message delivery logic ready
starting error log relay                                              ...done
starting networking                                                   ...done
starting notify cluster nodes                                         ...done
starting direct client                                                ...done

broker running
 
 
  感兴趣的话,可以输出rabbit:boot_steps()看一下,内容略长,请展开:
 
Boot Step Dump
[{pre_boot,[{description,"rabbit boot start"}]},
{file_handle_cache,
     [{description,"file handle cache server"},
      {mfa,{rabbit,start_fhc,[]}},
      {requires,pre_boot},
      {enables,worker_pool}]},
{worker_pool,
     [{description,"worker pool"},
      {mfa,{rabbit_sup,start_supervisor_child,[worker_pool_sup]}},
      {requires,pre_boot},
      {enables,external_infrastructure}]},
{database,
     [{mfa,{rabbit_mnesia,init,[]}},
      {requires,file_handle_cache},
      {enables,external_infrastructure}]},
{database_sync,
     [{description,"database sync"},
      {mfa,{rabbit_sup,start_child,[mnesia_sync]}},
      {requires,database},
      {enables,external_infrastructure}]},
{codec_correctness_check,
     [{description,"codec correctness check"},
      {mfa,{rabbit_binary_generator,check_empty_frame_size,[]}},
      {requires,pre_boot},
      {enables,external_infrastructure}]},
{rabbit_exchange_type_recent_history_mnesia,
     [{description,"recent history exchange type: mnesia"},
      {mfa,{rabbit_exchange_type_recent_history,setup_schema,[]}},
      {requires,database},
      {enables,external_infrastructure}]},
{external_infrastructure,[{description,"external infrastructure ready"}]},
{rabbit_event,
     [{description,"statistics event manager"},
      {mfa,{rabbit_sup,start_restartable_child,[rabbit_event]}},
      {requires,external_infrastructure},
      {enables,kernel_ready}]},
{rabbit_log,
     [{description,"logging server"},
      {mfa,{rabbit_sup,start_restartable_child,[rabbit_log]}},
      {requires,external_infrastructure},
      {enables,kernel_ready}]},
{rabbit_registry,
     [{description,"plugin registry"},
      {mfa,{rabbit_sup,start_child,[rabbit_registry]}},
      {requires,external_infrastructure},
      {enables,kernel_ready}]},
{rabbit_auth_mechanism_amqplain,
     [{description,"auth mechanism amqplain"},
      {mfa,
          {rabbit_registry,register,
              [auth_mechanism,<<"AMQPLAIN">>,rabbit_auth_mechanism_amqplain]}},
      {requires,rabbit_registry},
      {enables,kernel_ready}]},
{rabbit_auth_mechanism_cr_demo,
     [{description,"auth mechanism cr-demo"},
      {mfa,
          {rabbit_registry,register,
              [auth_mechanism,<<"RABBIT-CR-DEMO">>,
               rabbit_auth_mechanism_cr_demo]}},
      {requires,rabbit_registry},
      {enables,kernel_ready}]},
{rabbit_auth_mechanism_plain,
     [{description,"auth mechanism plain"},
      {mfa,
          {rabbit_registry,register,
              [auth_mechanism,<<"PLAIN">>,rabbit_auth_mechanism_plain]}},
      {requires,rabbit_registry},
      {enables,kernel_ready}]},
{rabbit_exchange_type_direct,
     [{description,"exchange type direct"},
      {mfa,
          {rabbit_registry,register,
              [exchange,<<"direct">>,rabbit_exchange_type_direct]}},
      {requires,rabbit_registry},
      {enables,kernel_ready}]},
{rabbit_exchange_type_fanout,
     [{description,"exchange type fanout"},
      {mfa,
          {rabbit_registry,register,
              [exchange,<<"fanout">>,rabbit_exchange_type_fanout]}},
      {requires,rabbit_registry},
      {enables,kernel_ready}]},
{rabbit_exchange_type_headers,
     [{description,"exchange type headers"},
      {mfa,
          {rabbit_registry,register,
              [exchange,<<"headers">>,rabbit_exchange_type_headers]}},
      {requires,rabbit_registry},
      {enables,kernel_ready}]},
{rabbit_exchange_type_recent_history,
     [{description,"exchange type x-recent-history"},
      {mfa,
          {rabbit_registry,register,
              [exchange,<<"x-recent-history">>,
               rabbit_exchange_type_recent_history]}},
      {requires,rabbit_registry},
      {enables,kernel_ready}]},
{rabbit_exchange_type_topic,
     [{description,"exchange type topic"},
      {mfa,
          {rabbit_registry,register,
              [exchange,<<"topic">>,rabbit_exchange_type_topic]}},
      {requires,rabbit_registry},
      {enables,kernel_ready}]},
{kernel_ready,
     [{description,"kernel ready"},{requires,external_infrastructure}]},
{rabbit_node_monitor,
     [{description,"node monitor"},
      {mfa,{rabbit_sup,start_restartable_child,[rabbit_node_monitor]}},
      {requires,kernel_ready},
      {enables,core_initialized}]},
{delegate_sup,
     [{description,"cluster delegate"},
      {mfa,{rabbit,boot_delegate,[]}},
      {requires,kernel_ready},
      {enables,core_initialized}]},
{guid_generator,
     [{description,"guid generator"},
      {mfa,{rabbit_sup,start_restartable_child,[rabbit_guid]}},
      {requires,kernel_ready},
      {enables,core_initialized}]},
{rabbit_alarm,
     [{description,"alarm handler"},
      {mfa,{rabbit_alarm,start,[]}},
      {requires,kernel_ready},
      {enables,core_initialized}]},
{rabbit_memory_monitor,
     [{description,"memory monitor"},
      {mfa,{rabbit_sup,start_restartable_child,[rabbit_memory_monitor]}},
      {requires,rabbit_alarm},
      {enables,core_initialized}]},
{core_initialized,[{description,"core initialized"},{requires,kernel_ready}]},
{empty_db_check,
     [{description,"empty DB check"},
      {mfa,{rabbit,maybe_insert_default_data,[]}},
      {requires,core_initialized},
      {enables,routing_ready}]},
{background_gc,
     [{description,"background garbage collection"},
      {mfa,{rabbit_sup,start_restartable_child,[background_gc]}},
      {enables,networking}]},
{rabbit_mirror_queue_misc,
     [{description,"HA policy validation"},
      {mfa,
          {rabbit_registry,register,
              [policy_validator,<<"ha-mode">>,rabbit_mirror_queue_misc]}},
      {mfa,
          {rabbit_registry,register,
              [policy_validator,<<"ha-params">>,rabbit_mirror_queue_misc]}},
      {requires,rabbit_registry},
      {enables,recovery}]},
{rabbit_policy,
     [{description,"policy parameters"},
      {mfa,{rabbit_policy,register,[]}},
      {requires,rabbit_registry},
      {enables,recovery}]},
{recovery,
     [{description,"exchange, queue and binding recovery"},
      {mfa,{rabbit,recover,[]}},
      {requires,core_initialized},
      {enables,routing_ready}]},
{mirror_queue_slave_sup,
     [{description,"mirror queue slave sup"},
      {mfa,
          {rabbit_sup,start_supervisor_child,[rabbit_mirror_queue_slave_sup]}},
      {requires,recovery},
      {enables,routing_ready}]},
{mirrored_queues,
     [{description,"adding mirrors to queues"},
      {mfa,{rabbit_mirror_queue_misc,on_node_up,[]}},
      {requires,mirror_queue_slave_sup},
      {enables,routing_ready}]},
{routing_ready,
     [{description,"message delivery logic ready"},
      {requires,core_initialized}]},
{log_relay,
     [{description,"error log relay"},
      {mfa,{rabbit_error_logger,boot,[]}},
      {requires,routing_ready},
      {enables,networking}]},
{networking,[{mfa,{rabbit_networking,boot,[]}},{requires,log_relay}]},
{notify_cluster,
     [{description,"notify cluster nodes"},
      {mfa,{rabbit_node_monitor,notify_node_up,[]}},
      {requires,networking}]},
{direct_client,
     [{description,"direct client"},
      {mfa,{rabbit_direct,boot,[]}},
      {requires,log_relay}]}]

 

  最后小图一张:迅哥,周末愉快!