복붙노트

[SPRING] 스프링의 순환 의존성

SPRING

스프링의 순환 의존성

Spring은 이것을 어떻게 해결할 것인가? 빈 A는 빈 B에 의존하고, 빈 B는 빈 A에 의존한다.

해결법

  1. ==============================

    1.다른 답변에서 말했듯이, Spring은 단지 빈을 처리하고, 빈을 만들어 필요한만큼 주입합니다.

    다른 답변에서 말했듯이, Spring은 단지 빈을 처리하고, 빈을 만들어 필요한만큼 주입합니다.

    결과 중 하나는 XML 삽입 파일이 암시하는 것과 다른 순서로 빈 삽입 / 특성 설정이 발생할 수 있다는 것입니다. 따라서 속성 설정자가 이미 호출 된 다른 설정자에 의존하는 초기화를 수행하지 않도록주의해야합니다. 이것을 처리하는 방법은 bean을 InitializingBean 인터페이스를 구현하는 것으로 선언하는 것이다. 이를 위해서는 afterPropertiesSet () 메서드를 구현해야하며 여기에서 중요한 초기화를 수행해야합니다. (중요한 속성이 실제로 설정되었는지 확인하는 코드도 포함됩니다.)

  2. ==============================

    2.Spring 레퍼런스 매뉴얼은 순환 의존성이 어떻게 해결되는지 설명한다. 콩은 먼저 인스턴스화 된 다음 서로 주입됩니다.

    Spring 레퍼런스 매뉴얼은 순환 의존성이 어떻게 해결되는지 설명한다. 콩은 먼저 인스턴스화 된 다음 서로 주입됩니다.

    다음 클래스를 고려하십시오.

    package mypackage;
    
    public class A {
    
        public A() {
            System.out.println("Creating instance of A");
        }
    
        private B b;
    
        public void setB(B b) {
            System.out.println("Setting property b of A instance");
            this.b = b;
        }
    
    }
    

    그리고 비슷한 클래스 B :

    package mypackage;
    
    public class B {
    
        public B() {
            System.out.println("Creating instance of B");
        }
    
        private A a;
    
        public void setA(A a) {
            System.out.println("Setting property a of B instance");
            this.a = a;
        }
    
    }
    

    그런 다음이 구성 파일을 가지고 있다면 :

    <bean id="a" class="mypackage.A">
        <property name="b" ref="b" />
    </bean>
    
    <bean id="b" class="mypackage.B">
        <property name="a" ref="a" />
    </bean>
    

    이 구성을 사용하여 컨텍스트를 만들 때 다음과 같은 결과가 표시됩니다.

    Creating instance of A
    Creating instance of B
    Setting property a of B instance
    Setting property b of A instance
    

    a가 b에 주입되면, a는 아직 완전히 초기화되지 않습니다.

  3. ==============================

    3.코드베이스에서 (1 백만 줄 + 코드) 우리는 긴 시작 시간, 약 60 초에 문제가있었습니다. 우리는 12000+ FactoryBeanNotInitializedException을 얻고있었습니다.

    코드베이스에서 (1 백만 줄 + 코드) 우리는 긴 시작 시간, 약 60 초에 문제가있었습니다. 우리는 12000+ FactoryBeanNotInitializedException을 얻고있었습니다.

    내가 한 것은 AbstractBeanFactory # doGetBean에서 조건부 중단 점으로 설정되었습니다.

    catch (BeansException ex) {
       // Explicitly remove instance from singleton cache: It might have been put there
       // eagerly by the creation process, to allow for circular reference resolution.
       // Also remove any beans that received a temporary reference to the bean.
       destroySingleton(beanName);
       throw ex;
    }
    

    어디 그것을 destroySingleton 않습니다 (beanName) 나는 조건부 중단 점 코드 예외를 인쇄 :

       System.out.println(ex);
       return false;
    

    분명히 FactoryBeans가 순환 종속성 그래프에 포함되어있는 경우에 발생합니다. 우리는 ApplicationContextAware와 InitializingBean을 구현하고 수동으로 빈을 주입함으로써이를 해결했다.

    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    
    public class A implements ApplicationContextAware, InitializingBean{
    
        private B cyclicDepenency;
        private ApplicationContext ctx;
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext)
                throws BeansException {
            ctx = applicationContext;
        }
        @Override
        public void afterPropertiesSet() throws Exception {
            cyclicDepenency = ctx.getBean(B.class);
        }
    
        public void useCyclicDependency()
        {
            cyclicDepenency.doSomething();
        }
    }
    

    이것은 시작 시간을 약 15 초로 줄였습니다.

    그러니 항상 봄이 당신을 위해이 참조를 푸는 데 능숙하다고 가정하지 마십시오.

    이러한 이유로 많은 미래의 문제를 방지하기 위해 AbstractRefreshableApplicationContext # setAllowCircularReferences (false)를 사용하여 순환 종속성 해결을 비활성화하는 것이 좋습니다.

  4. ==============================

    4.그것은 단지 그것을합니다. 그것은 a와 b를 인스턴스화하고 각각을 다른 것에 삽입합니다 (setter 메소드 사용).

    그것은 단지 그것을합니다. 그것은 a와 b를 인스턴스화하고 각각을 다른 것에 삽입합니다 (setter 메소드 사용).

    뭐가 문제 야?

  5. ==============================

    5.Spring 레퍼런스 :

    Spring 레퍼런스 :

  6. ==============================

    6.Spring 컨테이너는 Setter 기반 순환 종속성을 해결할 수 있지만 생성자 기반 순환 종속성의 경우 런타임 예외 BeanCurrentlyInCreationException을 제공합니다. Setter 기반 순환 종속성의 경우 IOC 컨테이너는이를 주입하기 전에 공동 작업 빈을 완전히 구성하는 일반적인 시나리오와 다르게 처리합니다. 예를 들어, Bean A가 Bean C에 Bean B와 Bean B에 종속성이 있다면, 컨테이너는 B에 주입하기 전에 C를 완전히 초기화하고 B가 완전히 초기화되면 A에 주입됩니다. 그러나 순환 종속성의 경우 콩이 완전히 초기화되기 전에 콩에 주입됩니다.

    Spring 컨테이너는 Setter 기반 순환 종속성을 해결할 수 있지만 생성자 기반 순환 종속성의 경우 런타임 예외 BeanCurrentlyInCreationException을 제공합니다. Setter 기반 순환 종속성의 경우 IOC 컨테이너는이를 주입하기 전에 공동 작업 빈을 완전히 구성하는 일반적인 시나리오와 다르게 처리합니다. 예를 들어, Bean A가 Bean C에 Bean B와 Bean B에 종속성이 있다면, 컨테이너는 B에 주입하기 전에 C를 완전히 초기화하고 B가 완전히 초기화되면 A에 주입됩니다. 그러나 순환 종속성의 경우 콩이 완전히 초기화되기 전에 콩에 주입됩니다.

  7. ==============================

    7.명확하게 여기에 설명되어 있습니다. Eugen Paraschiv에게 감사드립니다.

    명확하게 여기에 설명되어 있습니다. Eugen Paraschiv에게 감사드립니다.

    순환 의존성은 디자인 냄새입니다. 문제를 해결하기 위해 의존성에 대해 @Lazy를 사용하거나 해결합니다.

  8. ==============================

    8.A가 B에 의존한다고하면, Spring은 먼저 A, B를 인스턴스화 한 다음 B에 대한 속성을 설정 한 다음 B를 A로 설정합니다.

    A가 B에 의존한다고하면, Spring은 먼저 A, B를 인스턴스화 한 다음 B에 대한 속성을 설정 한 다음 B를 A로 설정합니다.

    B가 A에 의존한다면?

    내 이해가있다 : 봄 방금 A 생성 된 (생성자 실행), 있지만 완전히 초기화되지 않은 (모든 주입 완료되지 않음), 음, 그것은 괜찮아요, 그것은 허용되지 않는 완전히 A 초기화되지 않은, 지금 A 인스턴스를 B로 완전히 초기화했습니다. B가 완전히 초기화 된 후 A로 설정되고 마지막으로 A가 완전히 시작되었습니다.

    즉, A를 B에 미리 노출하기 만하면됩니다.

    Constructor를 통한 의존성에 대해 Sprint는 BeanCurrentlyInCreationException을 throw합니다.이 예외를 해결하려면 constructor-arg 방식을 통해 다른 bean에 의존하는 bean에 대해 lazy-init을 true로 설정하십시오.

  9. ==============================

    9.문제 ->

    문제 ->

    Class A {
        private final B b; // must initialize in ctor/instance block
        public A(B b) { this.b = b };
    }
    
    
    Class B {
        private final A a; // must initialize in ctor/instance block
        public B(A a) { this.a = a };
     }
    

    // 원인 : org.springframework.beans.factory.BeanCurrentlyInCreationException : 이름이 'A'인 bean을 생성하는 중 오류가 발생했습니다. 요청한 bean이 현재 생성 중입니다. 해결할 수없는 순환 참조가 있습니까?

    해결책 1 ->

    Class A {
        private B b; 
        public A( ) {  };
        //getter-setter for B b
    }
    
    Class B {
        private A a;
        public B( ) {  };
        //getter-setter for A a
    }
    

    해결책 2 ->

    Class A {
        private final B b; // must initialize in ctor/instance block
        public A(@Lazy B b) { this.b = b };
    }
    
    Class B {
        private final A a; // must initialize in ctor/instance block
        public B(A a) { this.a = a };
    }
    
  10. ==============================

    10.일반적으로 constructor-injection을 사용하고 property-injection으로 전환하고 싶지 않다면 Spring의 lookup-method-injection은 하나의 bean을 다른 bean을 lazily lookup하고 따라서 cyclic dependency를 해결할 수있게합니다. 다음을 참조하십시오 : http://docs.spring.io/spring/docs/1.2.9/reference/beans.html#d0e1161

    일반적으로 constructor-injection을 사용하고 property-injection으로 전환하고 싶지 않다면 Spring의 lookup-method-injection은 하나의 bean을 다른 bean을 lazily lookup하고 따라서 cyclic dependency를 해결할 수있게합니다. 다음을 참조하십시오 : http://docs.spring.io/spring/docs/1.2.9/reference/beans.html#d0e1161

  11. ==============================

    11.Setter Injection 또는 Field Injection을 사용하거나 의존성을 위해 @Lazy를 사용합니다.

    Setter Injection 또는 Field Injection을 사용하거나 의존성을 위해 @Lazy를 사용합니다.

  12. ==============================

    12.두 개의 bean이 서로 종속되어 있다면 두 bean 정의 모두에서 Constructor injection을 사용해서는 안됩니다. 대신 콩 중 하나에서 세터 주입을 사용해야합니다. (물론 bean 정의와 setter injection을 둘 다 사용할 수 있지만, 양쪽 모두에서 생성자 주입은 'BeanCurrentlyInCreationException'

    두 개의 bean이 서로 종속되어 있다면 두 bean 정의 모두에서 Constructor injection을 사용해서는 안됩니다. 대신 콩 중 하나에서 세터 주입을 사용해야합니다. (물론 bean 정의와 setter injection을 둘 다 사용할 수 있지만, 양쪽 모두에서 생성자 주입은 'BeanCurrentlyInCreationException'

    Spring 문서 ( "https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#resources-resource")를 참조하십시오.

  13. ==============================

    13.봄 콩 사이에 순환 의존성이 있으면 생성자 삽입이 실패합니다. 이 경우 우리는 Setter 주입을 통해 문제를 해결할 수 있습니다.

    봄 콩 사이에 순환 의존성이 있으면 생성자 삽입이 실패합니다. 이 경우 우리는 Setter 주입을 통해 문제를 해결할 수 있습니다.

    기본적으로 Constructor Injection은 필수 종속성에 유용합니다. 선택적인 종속성은 Setter injection을 사용하는 것이 더 좋습니다. 왜냐하면 우리가 재 주입을 할 수 있기 때문입니다.

  14. from https://stackoverflow.com/questions/3485347/circular-dependency-in-spring by cc-by-sa and MIT license