How does Spring solve circular dependencies

As projects continue to grow, so does the complexity of dependencies. In this case, the circular dependency problem is particularly prominent. As a widely used Java enterprise application development framework, the Spring framework provides developers with an elegant solution to deal with circular dependencies. In this article, we'll explore how Spring resolves circular dependencies.

What is a circular dependency?

Circular dependency refers to the existence of interdependence between two or more beans, resulting in the inability to create a complete object. For example, Bean A depends on Bean B, and Bean B also depends on Bean A, forming a dependency cycle. This situation can cause object instances to not be created properly, making the entire application inoperable.

How does Spring resolve circular dependencies?

The Spring Framework uses a technique called "three-level caching" to resolve circular dependencies. Specifically, the three-level cache is as follows:

  1. Level 1 cache (Singleton Objects): Stores the Bean instances that have been created, that is, complete objects.
  2. L2 cache (Early Singleton Objects): Stores Bean instances that are in the process of being created, that is, objects that have not yet completed attribute injection.
  3. Three-level cache (Singleton Factories): Stores the factory object of the Bean instance, which is used to obtain the complete Bean instance that has not yet been created.

The Spring framework follows the following steps in the process of creating beans:

  1. First check whether the Bean instance exists in the first-level cache, and return directly if it exists.
  2. If it does not exist in the first-level cache, then check whether the Bean instance exists in the second-level cache, and return directly if it exists.
  3. If it still does not exist in the second-level cache, then get the factory object of the Bean instance from the third-level cache, and call its getObject method to create the Bean instance. During this process, the newly created Bean instance will be added to the second-level cache.
  4. When the dependencies of the Bean are processed, the Bean instance is moved from the second-level cache to the first-level cache, and the corresponding factory object is deleted from the third-level cache.

Through this three-level caching mechanism, Spring can solve the circular dependency problem in the process of creating beans. When a circular dependency is encountered, because the interdependent Bean instance is already in the second-level cache, it can be directly obtained and injected, thereby avoiding the deadlock phenomenon.

It should be noted that the Spring framework only supports resolving circular dependencies in Singleton scope. For beans with prototype (Prototype) scope, since a new instance is created every time a bean is obtained, Spring cannot solve the circular dependency problem in this case.

How to avoid circular dependencies?

Although the Spring framework can solve the problem of circular dependencies, in the actual development process, it is best to avoid circular dependencies as much as possible. Here are some suggestions:

  1. Reasonably divide modules and packages: By organizing classes with similar functions in the same package or module, the risk of circular dependencies can be reduced.
  2. Use interface isolation: When you need to rely on another class, try to rely on the interface instead of the concrete implementation class. This reduces the degree of coupling between classes and reduces the possibility of circular dependencies.
  3. Dependency Inversion Principle: Follow the Dependency Inversion Principle, that high-level modules should not depend on low-level modules, both should depend on abstractions. This helps reduce the coupling between modules, thereby avoiding circular dependencies.

Summarize

By introducing a three-level cache mechanism, the Spring framework can solve the circular dependency problem in the process of creating singleton-scoped beans. However, in actual development, we should try to avoid the generation of circular dependencies to reduce system complexity and maintenance costs. Following design principles such as modularity, interface isolation, and dependency inversion principles can help us better manage code and reduce the risk of circular dependencies.

Guess you like

Origin blog.csdn.net/kaka_buka/article/details/129985821