Kai Tao Spring3 (3.2)-Di's cyclic dependence

Source: Internet
Author: User
Tags throwable

3.2.1 What is cyclic dependency

A cyclic dependency is a circular reference in which two or more beans hold each other, such as Circlea reference Circleb,circleb reference Circlec,circlec reference Circlea, and they are eventually reflected as a ring. This is not a circular call, and a circular call is a ring call between methods. 3-5 is shown below:

Figure 3-5 Circular Reference

Circular calls cannot be resolved unless there is an end condition, otherwise it is a dead loop that eventually results in a memory overflow error.

Spring container loop dependency includes constructor loop dependency and setter loop dependency, how does the spring container solve the cyclic dependency? Let's start by defining a circular reference class:

     PackageCn.javass.spring.chapter3.bean;  Public classCirclea {PrivateCircleb Circleb;  PublicCirclea () {} PublicCirclea (Circleb circleb) { This. Circleb =Circleb; }       Public voidSetcircleb (Circleb circleb) { This. Circleb =Circleb; }       Public voidA () {circleb.b (); }      }  
     PackageCn.javass.spring.chapter3.bean;  Public classCircleb {PrivateCirclec Circlec;  PublicCircleb () {} PublicCircleb (Circlec circlec) { This. Circlec =Circlec; }       Public voidSetcirclec (Circlec circlec) { This. Circlec =Circlec; }           Public voidB () {circlec.c (); }      }  
     PackageCn.javass.spring.chapter3.bean;  Public classCirclec {PrivateCirclea Circlea;  PublicCirclec () {} PublicCirclec (Circlea circlea) { This. Circlea =Circlea; }       Public voidSetcirclea (Circlea circlea) { This. Circlea =Circlea; }           Public voidC () {circlea.a (); }      }  
3.2.2 How spring solves cyclic dependencies

constructor Cyclic dependency: represents a cyclic dependency that is composed of a constructor injection, which cannot be resolved, only throws a beancurrentlyincreationexception exception to indicate a cyclic dependency.

For example, when creating the Circlea class, the constructor needs the Circleb class, which will create the Circleb, and when the Circleb class is created, the Circlec class is found, then the Circlec is created, and the Circlec is eventually found and Circlea is needed. ; thus forming a ring, no way to create.

The Spring container places each bean identifier that is being created in a "currently created bean Pool", and the bean identifier remains in the pool during creation, so if you find yourself in the "Currently creating bean pool" during the creation of the bean The beancurrentlyincreationexception exception is thrown to indicate a cyclic dependency, and the created Bean is purged from the currently created Bean pool.

1) First let's look at the configuration file (Chapter3/circleinjectbyconstructor.xml):

<BeanID= "Circlea"class= "Cn.javass.spring.chapter3.bean.CircleA">  <Constructor-argIndex= "0"ref= "Circleb"/>  </Bean>  <BeanID= "Circleb"class= "Cn.javass.spring.chapter3.bean.CircleB">  <Constructor-argIndex= "0"ref= "Circlec"/>  </Bean>  <BeanID= "Circlec"class= "Cn.javass.spring.chapter3.bean.CircleC">  <Constructor-argIndex= "0"ref= "Circlea"/>  </Bean>  

2) write the test code (cn.javass.spring.chapter3.CircleTest) test it:

@Test (expected = beancurrentlyincreationexception.class)       Public voidTestcirclebyconstructor ()throwsThrowable {Try {            NewClasspathxmlapplicationcontext ("Chapter3/circleinjectbyconstructor.xml"); }          Catch(Exception e) {//because it is to be thrown when creating circle3;Throwable e1 =e.getcause (). Getcause (). Getcause (); ThrowE1; }      }  

Let's analyze It:

1, Spring container to create "Circlea" bean, first go to "Create bean pool" to find out if the current bean is being created, if not found, continue to prepare its required constructor parameter "Circleb", and put "Circlea" identifier " Current Create Bean Pool ";

2, Spring container to create "Circleb" bean, first go to "Create bean pool" to find out if the current bean is being created, if not found, continue to prepare its required constructor parameter "Circlec", and put "Circleb" identifier " Current Create Bean Pool ";

3, Spring container to create "Circlec" bean, first go to "Create bean pool" to find out if the current bean is being created, if not found, continue to prepare its required constructor parameter "Circlea", and put "Circlec" identifier " Current Create Bean Pool ";

4. To this end, the spring container is going to create the "Circlea" bean, and the bean identifier is found in the "currently created Bean Pool" because it represents a cyclic dependency and throws beancurrentlyincreationexception.

second, setter cyclic dependency: indicates a cyclic dependency formed by setter injection method.

The dependency on setter injection is done through the spring container exposing beans that have just completed the constructor injection but not completing other steps (such as setter injection), and can only resolve the bean loop dependency of the singleton scope.

As shown in the following code, by exposing a singleton factory method prematurely, the other bean can be referenced to that bean.

New objectfactory () {      publicthrows  beansexception {          return  Getearlybeanreference (Beanname, MBD, Bean);      }  );  

The steps are as follows:

1. The spring container creates a singleton "Circlea" Bean, which first creates a bean based on the parameterless constructor and exposes a "objectfactory" to return a bean that is exposed in advance and puts the "Circlea" identifier in the " The bean pool is currently created, and then the setter is injected with "Circleb";

2. The spring container creates a singleton "Circleb" Bean, which first creates a bean based on the parameterless constructor and exposes a "objectfactory" to return a bean that is exposed in advance and puts the "Circleb" identifier in the " Currently create Bean Pool ", then the setter injected" Circlec ";

3. The spring container creates a singleton "Circlec" Bean, which first creates a bean based on the parameterless constructor and exposes a "objectfactory" to return a bean that is exposed in advance and puts the "Circlec" identifier in the " The bean pool is currently created, and then the setter is injected with "Circlea", and the "Circlea" is injected into the "objectfactory" factory so that it can be used to return a created bean in advance by exposing it prematurely;

4, finally in the dependency injection "Circleb" and "Circlea", complete setter injection.

Dependency injection cannot be completed for the "prototype" Scope bean,spring container because the bean,spring container of the "prototype" scope is not cached, so it is not possible to expose a created bean in advance.

    <!--define the bean configuration file, and note that scope is "prototype" -      <BeanID= "Circlea"class= "Cn.javass.spring.chapter3.bean.CircleA"Scope= "Prototype">              < Propertyname= "Circleb"ref= "Circleb"/>         </Bean>         <BeanID= "Circleb"class= "Cn.javass.spring.chapter3.bean.CircleB"Scope= "Prototype">             < Propertyname= "Circlec"ref= "Circlec"/>         </Bean>         <BeanID= "Circlec"class= "Cn.javass.spring.chapter3.bean.CircleC"Scope= "Prototype">             < Propertyname= "Circlea"ref= "Circlea"/>         </Bean>  

    //Test Code Cn.javass.spring.chapter3.CircleTest@Test (expected = beancurrentlyincreationexception.class)       Public voidTestcirclebysetterandprototype ()throwsThrowable {Try{Classpathxmlapplicationcontext CTX=NewClasspathxmlapplicationcontext ("Chapter3/circleinjectbysetterandprototype.xml"); System.out.println (Ctx.getbean ("Circlea")); }          Catch(Exception e) {throwable e1=e.getcause (). Getcause (). Getcause (); ThrowE1; }      }  

For the "singleton" Scope bean, you can pass "setallowcircularreferences (false);" To disable circular references:

@Test (expected = beancurrentlyincreationexception.class)       Public voidTestCircleBySetterAndSingleton2 ()throwsThrowable {Try{Classpathxmlapplicationcontext CTX=NewClasspathxmlapplicationcontext (); Ctx.setconfiglocation ("Chapter3/circleinjectbysetterandsingleton.xml");          Ctx.refresh (); }          Catch(Exception e) {throwable e1=e.getcause (). Getcause (). Getcause (); ThrowE1; }      }  

Add: The emergence of cyclic dependence is a design problem, be sure to avoid!

Please refer to the "no-loop Reliance" principle in agile Software development: principles, patterns and practices

The dependency structure between packages must be a direct acyclic graph (DAG). In other words, loops are not allowed in the dependency structure (circular dependencies). 

Kai Tao Spring3 (3.2)-Di's cyclic dependence

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.