Source: blog.csdn.net/u010644448

Introduction: A cyclic dependency is a loop of nested references in N classes. If we use new objects in daily development, the program will continue to be called at runtime until the memory runs out of error. Let’s talk about how Spring addresses loop dependencies.

First: constructor parameter cyclic dependencies

The Spring container places each Bean identifier being created in a currently created Bean pool, where the Bean identifier remains during creation.

So if in the process of creating Bean has found itself in the “current to create large pools of Bean” will be thrown when abnormal BeanCurrentlyInCreationException said circular dependencies; Beans that have been created are cleared from the currently created Bean pool.

First we initialize three beans.

public class StudentA {    private StudentB studentB ;    public void setStudentB(StudentB studentB) {        this.studentB = studentB;    }    public StudentA() {    }    public StudentA(StudentB studentB) {        this.studentB = studentB;    }}public class StudentB {    private StudentC studentC ;    public void setStudentC(StudentC studentC) {        this.studentC = studentC;    }    public StudentB() {    }    public StudentB(StudentC studentC) {        this.studentC = studentC;    }}public class StudentC {    private StudentA studentA ;    public void setStudentA(StudentA studentA) {        this.studentA = studentA;    }    public StudentC() {    }    public StudentC(StudentA studentA) {        this.studentA = studentA;    }}
Copy the code

StudentA has the parameter construct StudentB. The parameterized construct for StudentB is StudentC, and the parameterized construct for StudentC is StudentA. This creates a loop-dependent situation where we hand all three beans over to Spring and instantiate them with the parameterized construct.

 <bean id="a" class="com.zfx.student.StudentA">        <constructor-arg index="0" ref="b"></constructor-arg>    </bean>    <bean id="b" class="com.zfx.student.StudentB">        <constructor-arg index="0" ref="c"></constructor-arg>    </bean>    <bean id="c" class="com.zfx.student.StudentC">        <constructor-arg index="0" ref="a"></constructor-arg>    </bean>
Copy the code

Here are the test classes:

public class Test {    public static void main(String[] args) {        ApplicationContext context = new ClassPathXmlApplicationContext("com/zfx/student/applicationContext.xml");        //System.out.println(context.getBean("a", StudentA.class));    }}
Copy the code

The following error information is displayed:

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException:    Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
Copy the code

The Spring container creates the singleton StudentA, which relies on StudentB, and places A in the “currently created Bean pool”. At this time to create StudentB, StudentC StudentB dependence, and then will be placed in the “current to create large pools of Bean” B, so creating StudentC StudentC rely on StudentA again, however, as the Student in the pool, complains, so, Since the beans in the pool are not initialized, they rely on an error.

Second: setter singleton, default

To talk about setter injection, it is best to look at a diagram of Bean instantiation in Spring

The first two steps in the figure show that Spring instantiates the Bean object before setting the object properties

Example Modify the configuration file to be injected in set mode

<! --scope="singleton" --> <bean id="a" class="com.zfx.student.StudentA" scope="singleton" name="studentB" ref="b"></property> </bean> <bean id="b" class="com.zfx.student.StudentB" scope="singleton"> <property name="studentC" ref="c"></property> </bean> <bean id="c" class="com.zfx.student.StudentC" scope="singleton"> <property name="studentA" ref="a"></property> </bean>Copy the code

Here are the test classes:

public class Test {    public static void main(String[] args) {        ApplicationContext context = new ClassPathXmlApplicationContext("com/zfx/student/applicationContext.xml");        System.out.println(context.getBean("a", StudentA.class));    }}
Copy the code

The printed result is:

com.zfx.student.StudentA@1fbfd6
Copy the code

Why don’t we get an error when we use set?

Spring instantiates the Bean object with a construct, puts the instantiated object into a Map, and provides a way to get a reference to the instantiated object with an unset property.

When Spring instantiates StudentA, StudentB, and StudentC, Spring sets the properties of the StudentA, StudentB, and c objects, and StudentA, which relies on StudentB, obtains the singleton from the Map, and so on. There won’t be a loop problem.

Here’s how to do it in the Spring source code. The following source code in the Spring Bean bag DefaultSingletonBeanRegistry. Java classes

/** Cache of singleton objects: Bean name --> bean instance (cache singleton instance Map collection) */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64); /** Cache of singleton factories: Bean name --> ObjectFactory (singleton factory bean cache) */ private final Map<String, ObjectFactory> singletonFactories = new HashMap<String, ObjectFactory>(16); /** Cache of early singleton objects: Bean name --> bean instance (early single object cache collection) */ private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16); /** Set of registered singletons, Containing the bean names in registration order private final Set<String> registeredSingletons = new LinkedHashSet<String>(64); Add the given singleton factory for building the specified singleton * if necessary. * <p>To be called for eager registration of singletons, e.g. to be able to * resolve circular references. * @param beanName the name of the bean * @param singletonFactory the factory for the singleton object */ protected void addSingletonFactory(String beanName, ObjectFactory singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { if (! this.singletonObjects.containsKey(beanName)) { this.singletonFactories.put(beanName, singletonFactory); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); }}}Copy the code

Third kind: setter way prototype, prototype

Modify the configuration file to:

<bean id="a" class="com.zfx.student.StudentA" scope="prototype">        <property name="studentB" ref="b"></property>    </bean>    <bean id="b" class="com.zfx.student.StudentB" scope="prototype">        <property name="studentC" ref="c"></property>    </bean>    <bean id="c" class="com.zfx.student.StudentC" scope="prototype">        <property name="studentA" ref="a"></property>    </bean>
Copy the code

Scope =”prototype” means that each request creates an instance object.

The difference is that stateful beans both use the Prototype scope, while stateless beans generally use the Singleton singleton scope.

Test cases:

public class Test { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("com/zfx/student/applicationContext.xml"); Println (context.getBean("a", StudentA. Class)); // If scope="prototype", system.out.println (context.getbean ("a", StudentA. }}Copy the code

Print result:

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException:    Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
Copy the code

Why is the prototype pattern wrong?

For “prototype-scoped beans, the Spring container cannot do dependency injection because the Spring container does not cache” prototype-scoped beans, so it cannot expose a Bean being created in advance.

Some interview questions for 2020 are summarized. The interview questions are divided into 19 modules, which are: Java Basics, Containers, Multithreading, Reflection, object copy, JavaWeb exceptions, Networking, Design Patterns, Spring/SpringMVC, SpringBoot/SpringCloud, Hibernate, MyBatis, RabbitMQ, Kafka, Zookeep Er, MySQL, Redis, JVM.

Get information: pay attention to the public number: [programmers with stories], get learning materials, remember to point a concern + comments oh ~