복붙노트

[SPRING] 싱글 톤의 여러 인스턴스를 만드는 봄?

SPRING

싱글 톤의 여러 인스턴스를 만드는 봄?

나는 서로를 autowire하는 Spring beans 그래프를 가지고있다. 심하게 단순화 된 그림 :

<context:annotation-config/>
<bean class="Foo"/>
<bean class="Bar"/>
<bean class="Baz"/>

...

public class Foo {
   @Autowired Bar bar;
   @Autowired Baz baz;
}

public class Bar {
   @Autowired Foo foo;
}

public class Baz {
   @Autowired Foo foo;
}

이 콩들은 모두 싱글 톤임을 암시하는 범위를 지정하지 않습니다. 명시 적 싱글 톤을 사용하면 아무 것도 바뀌지 않습니다.

문제는 단일 응용 프로그램 컨텍스트를 인스턴스화 한 후에 Bar 및 Baz 인스턴스에 Foo의 다른 인스턴스가 포함되어 있다는 것입니다. 어떻게 이런 일이 일어날 수 있겠습니까?

나는 Foo를위한 args 생성자를 public으로 만들지 않으려 고 노력했다. 그리고 디버깅은 Foo가 두 번 이상 생성되었다는 것을 확인했다. 이 모든 작업에 대한 스택 추적이 여기에 있습니다.

나는 또한 Spring을위한 디버그 로깅을 가능하게하려고 노력했으며 다른 모든 라인들도 다음과 같은 것을 가지고있다.

DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo'
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo'
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo'

콩이 상호 참조하는 것을 이해합니다.하지만 스프링 프레임 워크가 싱글 톤 범위를 존중하고 싱글 톤 빈을 한 번 초기화 한 다음 원하는 곳으로 돌려 보내주기를 기대합니다.

흥미로운 사실은 public static Foo getInstance 접근자를 사용하여 오래된 학교 전용 생성자를 사용하면 올바르게 작동한다는 것입니다. 컨텍스트 설정 중에 예외가 throw되지 않습니다.

FWIW, o.s.c.s.ClassPathXmlApplicationContext (String ... configLocations) 생성자를 사용하여 Spring 버전 3.0.5 (또한 3.1.2, 동일한 결과로 시도)를 사용하고 있습니다.

정적 이니셜 라이저를 사용하도록 코드를 쉽게 변환 할 수 있지만 Spring이 이런 식으로 동작하는 이유를 이해하고 싶습니다. 이거 버그 야?

편집 : 일부 추가 조사에 따르면

위의 내용은 @Autowired 구현과 관련된 스프링 버그임을 제안합니다. 내가 유용한 것을 얻는다면 Spring Community forums에 글을 올리고 여기에 글을 올리겠다.

해결법

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

    1.컨텍스트에주의하지 않으면 하위 컨텍스트가 동일한 싱글 톤 Bean을 다시 구성 할 수 있습니다 : 구성 요소 스캔 주석 (다른 Spring 컨텍스트 스캔 주석도 MVC와 다른 것들처럼 있습니다). 웹 애플리케이션에서 Spring 서블릿을 사용할 때 흔히 발생하는 문제입니다 (DispatcherServlet이 다른 애플리케이션 컨텍스트를 만드는 이유 참조).

    컨텍스트에주의하지 않으면 하위 컨텍스트가 동일한 싱글 톤 Bean을 다시 구성 할 수 있습니다 : 구성 요소 스캔 주석 (다른 Spring 컨텍스트 스캔 주석도 MVC와 다른 것들처럼 있습니다). 웹 애플리케이션에서 Spring 서블릿을 사용할 때 흔히 발생하는 문제입니다 (DispatcherServlet이 다른 애플리케이션 컨텍스트를 만드는 이유 참조).

    하위 컨텍스트에서 구성 요소를 다시 스캔하지 않았는지 확인하거나 특정 패키지 / 주석 만 스캔하고 루트 컨텍스트 구성 요소 검사에서 해당 패키지 / 주석을 제외합니다.

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

    2.웬일인지 우리는 이것을 통합 테스트와 서비스에서 무작위로 띄우고있다 (스프링 4.1.4, 자바 1.8).

    웬일인지 우리는 이것을 통합 테스트와 서비스에서 무작위로 띄우고있다 (스프링 4.1.4, 자바 1.8).

    하나 이상의 범인이있는 것처럼 보입니다. Autowiring이 처음에는이 문제를 일으킨 것으로 보입니다.

    그러나 우리는 영향을받은 각 bean에게 'id'필드를 제공함으로써 가장 일관된 실패를 해결했습니다.

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

    3.생성자 방식 대신 setter injection을 사용하여 작동하는지 확인하십시오. 스프링 빈 xml에서 Bean B ref to Bean B를 지정하고 그 반대의 경우도 지정하십시오.

    생성자 방식 대신 setter injection을 사용하여 작동하는지 확인하십시오. 스프링 빈 xml에서 Bean B ref to Bean B를 지정하고 그 반대의 경우도 지정하십시오.

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

    4.내 Spring 구성은 다음과 같습니다.

    내 Spring 구성은 다음과 같습니다.

    <context:annotation-config/>
    
    <bean class="Bar" />
    <bean class="Foo" />
    <bean class="Baz" /> 
    

    수업은 당신과 동일합니다.

    다음과 같은 테스트 응용 프로그램 :

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class SpringTest {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("META-INF/spring/testctx.xml");
    
            Foo foo = ctx.getBean(Foo.class);
            Baz baz = ctx.getBean(Baz.class);
            Bar bar = ctx.getBean(Bar.class);
    
            System.out.println(foo.equals(baz.foo));
            System.out.println(foo.equals(bar.foo));
            System.out.println(baz.equals(foo.baz));
    
            System.out.println(foo.baz.toString());
            System.out.println(baz.toString());
            System.out.println(foo.bar.toString());
            System.out.println(bar.toString());
    
        }
    
    }
    

    다음과 같이 테스트 애플리케이션에서 출력됩니다.

    true
    true
    true
    Baz@8aef2b
    Baz@8aef2b
    Bar@215bf054
    Bar@215bf054
    

    3.0.6을 사용하면 완벽하게 작동합니다 (싱글 톤 빈은 실제로 싱글 톤입니다). 여기서 설명하지 않은 다른 것이 구성을 엉망으로 만들 수도 있습니다. 물론, 기본 노트를 사용하면 약간의 신비한 마술이 생길 수 있습니다 ;-)

  5. from https://stackoverflow.com/questions/11547240/spring-creating-multiple-instances-of-a-singleton by cc-by-sa and MIT license