2014-09-17 5 views
1

은 여기 간단한 예제 프로그램이 있습니다스프링 빈 객체 마샬링은 XML에 주어진 순서에 따라 달라 집니까?

package com.test; 

import org.springframework.beans.factory.InitializingBean; 
import org.springframework.context.support.FileSystemXmlApplicationContext; 

public class Main { 

    public static void main(String[] args) throws InterruptedException { 



     try { 
      FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("TestBeanFile.xml"); 
      Object o = context.getBean("AInstance"); 
     } 
     catch (Throwable e) { 
      e.printStackTrace(); 
     } 
     Thread.sleep(Long.MAX_VALUE); 
    } 

    private static class A implements InitializingBean { 
     private B myB; 

     public A() { 
      System.out.println("A constructor"); 
     } 

     public void setB(B aB) { 
      myB = aB; 
     } 

     @Override 
     public void afterPropertiesSet() throws Exception { 
      System.out.println("A aps"); 
     } 
    } 

    private static class B implements Runnable, InitializingBean { 
     private C myC; 
     private volatile boolean exit = false; 

     public B() { 
      System.out.println("B constructor"); 
     } 

     public void setC(C aC) { 
      myC = aC; 
     } 

     @Override 
     public void afterPropertiesSet() throws Exception { 
      System.out.println("B aps"); 
      if (myC == null) throw new IllegalArgumentException("C cannot be null"); 
      new Thread(this).start();   
     } 

     public void exit() { 
      exit = true; 
     } 

     @Override 
     public void run() { 
      while (!exit) { 
       System.out.println(myC.getValue()); 
       try { 
        Thread.sleep(1000); 
       } 
       catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      } 
     } 


    } 

    private static class C implements InitializingBean { 
     private String value = "C's value"; 

     public C() { 
      System.out.println("C constructor"); 
     } 

     public String getValue() { 
      return value; 
     } 

     @Override 
     public void afterPropertiesSet() throws Exception { 
      System.out.println("C aps"); 
     } 
    } 

} 

을 그리고 여기에 콩에 대한 간단한 XML 의도적으로 클래스에 잘못된 완전한 이름을 가지고있는 그들을로드입니다. 이것은 C B와 A가 만들어지지 않는다는 것을 의미합니다.

<?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:int="http://www.springframework.org/schema/integration" 
    xmlns:int-stream="http://www.springframework.org/schema/integration/stream" 
    xmlns:int-ip="http://www.springframework.org/schema/integration/ip" 
    xsi:schemaLocation=" 
      http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
      http://www.springframework.org/schema/integration   http://www.springframework.org/schema/integration/spring-integration-2.1.xsd 
      http://www.springframework.org/schema/integration/stream http://www.springframework.org/schema/integration/stream/spring-integration-stream-2.1.xsd 
      http://www.springframework.org/schema/integration/ip  http://www.springframework.org/schema/integration/ip/spring-integration-ip-2.1.xsd"> 


    <bean id="CInstance" class = "com.test.Main.C" /> 

    <bean id="BInstance" class = "com.test.Main.B"> 
     <property name="C" ref="CInstance" /> 
    </bean> 

    <bean id="AInstance" class = "com.test.Main.A1"> 
     <property name="B" ref="BInstance"/> 
    </bean> 

</beans> 

위의 XML C 및 B를 사용하여이 응용 프로그램을 실행하면 A가 생성되지만 A는 생성되지 않습니다. 그것은 다음과 같은 출력을 생성합니다 (예외가 슬로우되면 스택 추적을 생략을,하지만 난 당신이 A는 건설되지 않습니다 보장) :

C constructor 
C aps 
B constructor 
B aps 
C's value 
C's value 
C's value 
....... // one a second 

이 같이하기 위해 XML을 수정하는 경우 :

<?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:int="http://www.springframework.org/schema/integration" 
    xmlns:int-stream="http://www.springframework.org/schema/integration/stream" 
    xmlns:int-ip="http://www.springframework.org/schema/integration/ip" 
    xsi:schemaLocation=" 
      http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
      http://www.springframework.org/schema/integration   http://www.springframework.org/schema/integration/spring-integration-2.1.xsd 
      http://www.springframework.org/schema/integration/stream http://www.springframework.org/schema/integration/stream/spring-integration-stream-2.1.xsd 
      http://www.springframework.org/schema/integration/ip  http://www.springframework.org/schema/integration/ip/spring-integration-ip-2.1.xsd"> 

    <bean id="AInstance" class = "com.test.Main.A1"> 
     <property name="B" ref="BInstance"/> 
    </bean> 

    <bean id="BInstance" class = "com.test.Main.B"> 
     <property name="C" ref="CInstance" /> 
    </bean> 

    <bean id="CInstance" class = "com.test.Main.C" /> 
</beans> 

유일한 출력은 스택 추적이며 B 및 C 개체는 전혀 생성되지 않습니다.

이것은 봄에 벌레처럼 보입니다. 개체의 마샬링 및 XML에서 나타나는 순서에 따라 실행되는 생성자/afterpropertiesSet 메서드가 왜 이해가 안되는지. 이것이 나를 위해 무엇을 의미하는지, 그 클래스의 생성자/속성을 설정 한 후에 스레드를 구성 할 때 XML의 요소를 어떻게 정렬하는지 조심하지 않으면 리소스가 누출 될 수 있습니다. 이 예제에서는 A 클래스입니다. 왜냐하면 두 경우 모두 공사가 실패하기 때문입니다.

이렇게 버그입니까? 이해할 수없는 기능입니까? 이것이 기능이라면 bean 정의의 객체 그래프 대신에 XML 파일에 의존하여 마샬링 명령을 내리는 데 어떤 이유가 있을까요?

+0

'com.test.Main.A'가 아니라'com.test.Main.A1'이 될 수 있습니까? – mkobit

+0

@MikeKobit 그 의도는 의도적입니다. 이 예제는 빈 AInstance에 대한 잘못된 정규화 된 이름으로 인해 이러한 오브젝트를 작성해서는 안된다는 것을 demostrates합니다. 그러나 내가 주문하는 방법에 따라, 어쨌든 봄이 B와 C 클래스를 구성 할 가능성이 있습니다. –

답변

2

스프링은 먼저 <bean>과 XML 구성의 다른 요소를 읽고이를 정의하는 적절한 BeanDefinition 개체를 만듭니다.

그런 다음이를 초기화해야합니다. 이를 위해서는 명령을 결정해야합니다. bean이 다른 bean에 의존하지 않거나 @Order, 구현이 Ordered 및 몇 가지 다른 경우 (경우에 따라 다름)가없는 한 초기화 순서는 정의되지 않습니다.

첫 번째 예에서는 CInstance이 먼저 초기화됩니다. 그런 다음 BInstance이 초기화됩니다. 초기화의 일부는 비 데몬 스레드를 시작하는 afterPropertiesSet() 메소드 호출과 관련됩니다. 그러면 Spring은 AInstance을 초기화하려고 시도하고 실패합니다.

두 번째 예에서 Spring은 AInstance을 먼저 초기화하려고 시도합니다. 즉시 실패하고 두 번째 스레드를 시작하기 위해 변경하지 않습니다. AInstance 비록

<bean id="AInstance" class="com.example.Spring.A1"> 
    <property name="B" ref="BInstance" /> 
</bean> 

같은 선언에 BInstance에 따라

참고, 실제 인스턴스는 모든 속성 세터가 BBInstance를 할당하기 위해 호출되기 전에 초기화해야합니다. 그래서 스프링은 클래스를 인스턴스화하여 AInstance의 초기화를 시작합니다. 실패하면 전체 컨텍스트 새로 고침이 실패합니다. 전달되면 BInstance 빈을 초기화하고이를 사용하여 B 특성을 설정합니다.

+0

나는 내가 얻은 결과를 어떻게 받았는지 이해한다. 객체에 대한 의존성 체인이 변하지 않았고, XML만이 의미가 없다는 것을 이해해야한다. 나는 그들에게 일방적으로 명령한다, 나는 누출 자원을 갖지 않는다, 나는 그들에게 다른 것을 주문한다. 나에게 Spring은 B를 만들기 전에 A 클래스의 필수 유형을 찾을 수 있다는 것을 적어도 확인해야한다. B에서 C까지 동일하다.하지만 분명히 그렇지 않다. IMHO, 이는 이벤트 클래스의 정리가 필요한 리소스가있는 직렬화에 대한 수용 가능한 솔루션으로서 Spring을 거의 제거합니다. –

+0

@ MarkW 다시 연락 드리겠습니다. 나는 명령이 정의되지 않았 음을 확신한다. 당신이 사용할 수있는 트릭이있을 수 있습니다. –

+0

나는이 문제에 대한 스프링 기반 솔루션을 조사 중이며, 아마도 생성자 대 속성 주입을 조사하고 있습니까? 어쩌면 다른 사람들에게. 감사합니다. 감사합니다. –

관련 문제