@Lazy注解和<bean/>标签的lazy-init属性有什么区别?

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

按照我的理解,@Lazy注解和标签的lazy-init属性应该具有相同的功能。但是当我开发以下代码时,它显示出不同的行为。 在下面的代码中,我期待 :- (Circular Dependency Error)

org.springframework.beans.factory.BeanCurrentlyInCreationException

我使用@Lazy 批注附加了代码,按照我的预期,它不应允许循环依赖。

@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;
   }        
} 

主要 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 配置文件:

<?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>

输出:-

A.A() - 1 参数构造函数

B.B() - 1 参数构造函数

需要解释,为什么会这样?

来自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.

所以,在下面的代码中:

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

b 将在 首次访问时 而不是启动时注入(自动装配)。

现在,如果您将代码更改为以下内容:

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

你会看到 org.springframework.beans.factory.BeanCurrentlyInCreationException 被抛出。

您已经使用了一种机制来避免循环依赖,即在构造函数上使用 @Lazy。

请参阅此 link,其中解释了那是什么。在这里引用它:

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).

当你添加 public A(@Lazy B b) { .. } 通过使用@Lazy,Spring 将注入 B(通常是 CGLIB)的 Proxy 实例,而不是简单地 B。结果,它不需要创建一个实例,所以它工作了。 尝试删除 @Lazy,您将 运行 您提到的问题。

避免循环依赖的方法:

  1. 像你一样使用@Lazy
  2. 使用setter 注入而不是构造函数注入

link

中给出了更多技巧