What's the difference between @Lazy annotation and lazy-init attribute of <bean/> tag?

柔情痞子 提交于 2019-12-07 13:32:51

问题


As per my understanding, @Lazy annotation and lazy-init attribute of tag should have the same functionality. But when I developed the following code, it's showing distinct behaviours. In the following code, I was expecting :- (Circular Dependency Error)

org.springframework.beans.factory.BeanCurrentlyInCreationException

I have attached code using @Lazy annotation, as per my expectations it should not allow Circular Dependency.

@Component
public class A {
   private B b;
   @Autowired
   public A(@Lazy B b) {
         System.out.println("A.A() - 1-param Constructor");
         this.b = b;
   }    
}

@Component
public class B {
   private A a;
   @Autowired
   public B(A a) {
         System.out.println("B.B() - 1-param Constructor");
         this.a = a;
   }        
} 

Main Class :

public class AnnotationApp{
    public static void main(String[] args){
         ApplicationContext ctx = new ClassPathXmlApplicationContext("com/ry/cfgs/annotationAppContext.xml"); 
         B objB = ctx.getBean("b", B.class); 
         A objA = ctx.getBean("a", A.class);
    }
}

Spring Configuration File :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-4.3.xsd">

     <context:component-scan base-package="com.ry.beans.annotation"></context:component-scan>

</beans>

OUTPUT :-

A.A() - 1-param Constructor

B.B() - 1-param Constructor

Require explanation, why it's behaving like this?


回答1:


From Spring Framework Documentation:

... you can also place the @Lazy annotation on injection points marked with @Autowired or @Inject. In this context, it leads to the injection of a lazy-resolution proxy.

So, in the following code:

@Autowired
public A(@Lazy B b) {
    // ...
}

b will be injected (autowired) on first access instead of on startup.

Now, if you change your code to the following:

@Autowired
public A(@Lazy B b) {
    System.out.println("A.A() - 1-param Constructor");
    System.out.println(b.toString());
    this.b = b;
}

you will see that org.springframework.beans.factory.BeanCurrentlyInCreationException is thrown.




回答2:


You've already used one of mechanisms to avoid circular dependency by using @Lazy on the constructor.

See this link which explains what that is. Quoting it here:

Circular dependencies

If you use predominantly constructor injection, it is possible to create an unresolvable circular dependency scenario.

For example: Class A requires an instance of class B through constructor injection, and class B requires an instance of class A through constructor injection. If you configure beans for classes A and B to be injected into each other, the Spring IoC container detects this circular reference at runtime, and throws a BeanCurrentlyInCreationException.

One possible solution is to edit the source code of some classes to be configured by setters rather than constructors. Alternatively, avoid constructor injection and use setter injection only. In other words, although it is not recommended, you can configure circular dependencies with setter injection.

Unlike the typical case (with no circular dependencies), a circular dependency between bean A and bean B forces one of the beans to be injected into the other prior to being fully initialized itself (a classic chicken-and-egg scenario).

When you added public A(@Lazy B b) { .. } by using @Lazy, Spring will inject a Proxy instance of B (typically CGLIB) instead of simply B. As a result, it does NOT need to create an instance and so it worked. Try removing the @Lazy and you'll run to the issue you mentioned.

Ways to avoid Circular dependencies:

  1. Use @Lazy as you did
  2. Use setter injection instead of Constructor injection

Some more techniques are given in this link



来源:https://stackoverflow.com/questions/53924075/whats-the-difference-between-lazy-annotation-and-lazy-init-attribute-of-bean

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!