Explain in detail how to control the initialization order in two beans in spring

In the development process, there is a scenario where there are dependencies in the initialization logic of the two beans, and the initialization order of the two beans needs to be controlled. There can be a variety of implementation methods. Combined with the current understanding of spring, this paper tries to list several ideas.

scene

Suppose that both beans a and B need to read files from the local disk during initialization. The files loaded by B depend on the path configured in the global configuration file loaded in a, so a needs to initialize before B. in addition, after the configuration in a changes, it also needs to trigger B's reload logic, so a and B need to inject into each other.

For the following model, the problem is simplified to: we need inita () to be executed before initb ().

Scheme 1: Flag

We can control the initialization sequence of a and B in the business layer, set a "whether to initialize" flag in a, and check whether a can be initialized before B initialization. If not, call the initialization method of a, the so-called check and act. For the above model, the implementation is as follows:

Execution effect:

A construct B construct A init B init

The advantage of this flag setting method is that it can achieve lazy initialization. However, if there are many similar logic, the code is full of similar code everywhere, which is not elegant. Therefore, consider whether the framework itself can meet our needs.

Scheme 2: use dependson

The dependson annotation in spring can ensure that the dependent bean is created by the container before the current bean. However, if you don't understand the bean loading process in spring, you will misunderstand dependson, and you really stepped on the pit. For the above model, if the annotation @ dependson ({"a"}) is added to B, the execution result is:

A construct B construct B init A init

The key to the problem here is that the bean attribute is injected before initializing the method call.

In combination with this example, the actual situation is, because there is a cyclic dependency, A relies on B, loads B, and B relies on A, so an early exposure A is obtained, then B initialization method is invoked and then the A initialization method is returned. The specific source code analysis process is as follows:

ApplicationContext will load all no lazy singletons at the end of the refresh process.

In this example, first load bean a, and finally construct it through the parameterless constructor. Then, continue to populate the attribute bean and find that bean B needs to be injected. Therefore, load bean B instead (recursively call getbean()). At this point, bean B was found to need DependsOn ("a"). After saving dependencies (in order to prevent cyclic depends), calling getBean ("a"), and then getting bean A that was exposed in advance, so continuing the loading of B, the process is: initialization strategy constructing instance > attribute filling (also injecting the bean bean ahead of time) - > calling initialization method.

The process of obtaining bean a exposed in advance is as follows:

At this moment, the attribute injection of bean a is completed and returns to calling the initialization method, so the behavior is: construct a - > construct B - > b initialization - > a initialization.

Dependson only ensures that the dependent bean is instantiated and created before the current bean. Therefore, if you want to control the bean initialization sequence in this way, you can put the initialization logic in the constructor, but the complex and time-consuming logic imitation constructor is inappropriate, which will affect the system startup speed.

Scheme 3: before the container loads the bean

Many parts of the spring framework provide us with extension points, which well reflects the open close principle (OCP). Beanfactoryprocessor allows us to modify the beandefinition in the application context before the container loads any beans (the bean information parsed from the XML configuration file or configuration class is used for subsequent instantiation of beans).

In this example, you can put the initialization logic of a in a bean factory postprocessor.

Execution effect:

A init A construct B construct B init

This method puts the initialization logic in a before loading beans, which is very suitable for loading the global configuration of the system, but the initialization logic in this method cannot depend on the state of beans.

Scheme 4: order of event listener

Ordered in spring is also a very important component. Many logic will judge whether the object implements the ordered interface. If so, sorting will be performed first. For example, when an event is published, the obtained applicationlistener will be sorted first.

Therefore, the order of event listener in processing events can be used to realize the corresponding initialization logic in a and B respectively after the application context refresh is completed.

Execution effect:

A construct B construct A init B init

In this way, from the perspective of event response, after the context is loaded, first implement a logic, and then implement B logic.

summary

In normal development, you may use a language, the tip of the iceberg of a framework. With the deepening of language and framework, you will find more possibilities. This article is just an attempt based on the current understanding of the spring framework. There may be many ways to solve a problem, among which there must be trade-offs, which depends on the understanding of business and technology.

The above is the whole content of this article. I hope it will be helpful to your study, and I hope you can support programming tips.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>