In. net, we can use Attribute and reflection to parse Assembly metadata at runtime. Below is a simple example written by C:
Worker1 worker1 = new Worker1 (); var attribute = worker1.GetType().GetCustomAttribute(typeof( ProcessOrderAttribute)) as ProcessOrderAttribute ; Console.WriteLine("Description {0} Order {1}" , attribute.Descrption, attribute.Order); Console.ReadLine();[ProcessOrder( " first step", 1)] public class Worker1 { }class ProcessOrderAttribute : Attribute { public string Descrption { get; set; } public int Order { get; set; } public ProcessOrderAttribute(string description, int order) { Descrption = description; Order = order; } }
Similar to Erlang, we can also do similar things. We can use module_info to obtain module metadata, such:
(rabbit@nimbus)4> test:module_info().[{exports,[{module_info,0},{module_info,1}]},{imports,[]},{attributes,[{vsn,[64335248162526234078446821625873662118]}, {tag,[generated_by_tool]}]},{compile,[{options,[{d,use_specs}, {outdir,"/data/rabbitmq-server-3.0.0/ebin"}, {i,"/data/rabbitmq-server-3.0.0/include"}, debug_info]}, {version,"4.8"}, {time,{2012,12,12,14,39,42}}, {source,"/data/rabbitmq-server-3.0.0/src/test.erl"}]}](rabbit@nimbus)5>
Use metadata in rabbitmq
Rabbit_boot_stepTo control the startup process, for example, Rabbit. in ERL, every rabbit_boot_step defines the MFA, preconditions, and description information to be started. When rabbit is started, it starts up in order according to the element information of the module.
-rabbit_boot_step({rabbit_log, [{description, "logging server"}, {mfa, {rabbit_sup, start_restartable_child, [rabbit_log]}}, {requires, external_infrastructure}, {enables, kernel_ready}]}).-rabbit_boot_step({rabbit_event, [{description, "statistics event manager"}, {mfa, {rabbit_sup, start_restartable_child, [rabbit_event]}}, {requires, external_infrastructure}, {enables, kernel_ready}]}).-rabbit_boot_step({kernel_ready, [{description, "kernel ready"}, {requires, external_infrastructure}]}).
In the rabbit. erl module, we can see how rabbitmq parses module metadata and completes it.
start(normal, []) -> case erts_version_check() of ok -> {ok, Vsn} = application:get_key(rabbit, vsn), error_logger:info_msg("Starting RabbitMQ ~s on Erlang ~s~n", [Vsn, erlang:system_info(otp_release)]), {ok, SupPid} = rabbit_sup:start_link(), true = register(rabbit, self()), print_banner(), [ok = run_boot_step(Step) || Step <- boot_steps()], io:format("~nbroker running~n"), {ok, SupPid}; Error -> Error end. run_boot_step({StepName, Attributes}) -> Description = case lists:keysearch(description, 1, Attributes) of {value, {_, D}} -> D; false -> StepName end, case [MFA || {mfa, MFA} <- Attributes] of [] -> io:format("-- ~s~n", [Description]); MFAs -> io:format("starting ~-60s ...", [Description]), [try apply(M,F,A) catch _:Reason -> boot_error(Reason, erlang:get_stacktrace()) end || {M,F,A} <- MFAs], io:format("done~n"), ok end.boot_steps() -> sort_boot_steps(rabbit_misc:all_module_attributes(rabbit_boot_step)).
As for the implementation of rabbit_misc: all_module_attributes, it is easy to traverse and load the metadata of all modules:
\rabbitmq-server-3.0.0\src\rabbit_misc.erl all_module_attributes(Name) -> Modules = lists:usort( lists:append( [Modules || {App, _, _} <- application:loaded_applications(), {ok, Modules} <- [application:get_key(App, modules)]])), lists:foldl( fun (Module, Acc) -> case lists:append([Atts || {N, Atts} <- module_attributes(Module), N =:= Name]) of [] -> Acc; Atts -> [{Module, Atts} | Acc] end end, [], Modules). module_attributes(Module) -> case catch Module:module_info(attributes) of {'EXIT', {undef, [{Module, module_info, _} | _]}} -> io:format("WARNING: module ~p not found, so not scanned for boot steps.~n", [Module]), []; {'EXIT', Reason} -> exit(Reason); V -> V end.
Example of the call result:
(rabbit@nimbus)5> rabbit_misc:all_module_attributes(rabbit_boot_step).[{rabbit_policy,[{rabbit_policy,[{description,"policy parameters"}, {mfa,{rabbit_policy,register,[]}}, {requires,rabbit_registry}, {enables,recovery}]}]},{rabbit_mirror_queue_misc,[{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_exchange_type_topic,[{rabbit_exchange_type_topic,[{description,"exchange type topic"}, {mfa,{rabbit_registry,register, [exchange,<<"topic">>,rabbit_exchange_type_topic]}}, {requires,rabbit_registry},........
Extension: if we need to write rabbitmq extensions, We need to register the modules that rabbit knows about. This registration adds rabbit_boot_step to the modules, add our modules in the appropriate phase of rabbit startup. After registration, you can see the newly registered modules in the rabbit_registry table of ETS. For example, rabbit_exchange_type_recent_history is the newly added exchange.
(rabbit@nimbus)4> ets:i(rabbit_registry). <1 > {{exchange,'x-recent-history'},rabbit_exchange_type_recent_history}<2 > {{policy_validator,'ha-mode'},rabbit_mirror_queue_misc}<3 > {{policy_validator,'ha-params'},rabbit_mirror_queue_misc}<4 > {{auth_mechanism,'AMQPLAIN'},rabbit_auth_mechanism_amqplain}<5 > {{exchange,topic},rabbit_exchange_type_topic}<6 > {{runtime_parameter,policy},rabbit_policy}<7 > {{auth_mechanism,'PLAIN'},rabbit_auth_mechanism_plain}<8 > {{exchange,headers},rabbit_exchange_type_headers}<9 > {{auth_mechanism,'RABBIT-CR-DEMO'},rabbit_auth_mechanism_cr_demo}<10 > {{exchange,direct},rabbit_exchange_type_direct}<11 > {{exchange,fanout},rabbit_exchange_type_fanout}EOT (q)uit (p)Digits (k)ill /
I learned a trick with rabbitmq, and I am in a good mood. today, the heavy snow in Beijing reminds me of the beautiful sentence "watching Qingzhu change to qiongzhi when the six flowers go out to the house", a small figure (when I was a child, there was an identical cotton coat ):