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

时间:2018-12-25 16:45:34

标签: java spring circular-dependency spring-annotations spring-bean

据我了解,标签的@Lazy批注和lazy-init属性应具有相同的功能。但是,当我开发以下代码时,它表现出不同的行为。 在以下代码中,我期待的是:-(循环依赖项错误)

  

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

主类:

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-param构造函数

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

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

2 个答案:

答案 0 :(得分:2)

来自Spring Framework Documentation

  

...您还可以将@Lazy批注放置在标记的注入点上   @Autowired@Inject。在这种情况下,它导致注入   延迟解析代理服务器。

因此,在以下代码中:

@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

答案 1 :(得分:2)

您已经使用一种机制,通过在构造函数上使用@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).

添加时 通过使用@Lazy public A(@Lazy B b) { .. },Spring将注入B(通常为CGLIB)的代理实例,而不是简单的B。结果,它不需要创建实例,因此可以正常工作。 尝试删除@Lazy,您将遇到您提到的问题。

避免循环依赖的方法:

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

link

中提供了更多技术