2014-01-19 5 views
9

동적 bean 정의 변경 내용을 읽었습니다. 간단한 코드 예제 (아래 코드 참조)에서 시도해 보겠습니다. 서버를 멈추고 bean 정의를 추가/변경하고 싶지 않은 상황에서 매우 매력적입니다.스프링 컨텍스트 동적 변경

질문 :

  1. 그렇게 (아래 코드 참조) 않는 안전한가요?
  2. 나는 StaticApplicationContex 또는 BeanPostProcessor 또는 BeanFactoryPostProcessor의 도움으로 런타임에 빈 정의 변화를 달성 할 수 있음을 읽은? 그래서 차이점은 무엇입니까?

    public class Main { 
    final static String header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + 
         "<beans xmlns=\"http://www.springframework.org/schema/beans\"\n" + 
         "  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" + 
         "  xmlns:context=\"http://www.springframework.org/schema/context\"\n" + 
         "  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.xsd\">\n" + 
         " <context:annotation-config />\n" + 
         " <context:component-scan base-package=\"vbah\"/>"; 
    
    final static String contextA = 
         "<bean id=\"test\" class=\"java.lang.String\">\n" + 
           "\t\t<constructor-arg value=\"fromContextA\"/>\n" + 
           "</bean></beans>"; 
    
    final static String contextB = 
         "<bean id=\"test\" class=\"java.lang.String\">\n" + 
           "\t\t<constructor-arg value=\"fromContextB\"/>\n" + 
           "</bean></beans>"; 
    
    public static void main(String[] args) throws IOException { 
        //create a single context file 
        final File contextFile = new File("src/resources/spring-config.xml"); 
    
        //write the first context into it 
        FileUtils.writeStringToFile(contextFile, header + contextA); 
    
        //create a spring context 
        FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext(
          new String[]{contextFile.getPath()} 
        ); 
    
        //echo "fromContextA" 
        System.out.println(context.getBean("test")); 
    
        //write the second context into it 
        FileUtils.writeStringToFile(contextFile, header + contextB); 
    
        //refresh the context 
        context.refresh(); 
    
        //echo "fromContextB" 
        System.out.println(context.getBean("test")); 
    } 
    } 
    

편집 :

  1. 내가 BeanPostProcess을 알고있는 것처럼

    이미 수정 래핑하여 런타임에 빈 인스턴스를 존재 할 수 있습니다 :

    은 아래의 질문에 대답 할 수 프록시를 가지는 오브젝트 내가 맞습니까?

  2. AbstractApplicationContext # refresh() 모든 싱글 톤 빈을 삭제하고 다시 만듭니다.

    • 그러나 프로토 타입/사용자 정의 범위 bean의 정의를 변경하려면?
    • 만약 내가 두 개의 빈을 가지고 있다면 : A와 B.는 B에 대한 참조를 가지고있다. 빈 정의를 B의 정의를 포함하지 않는 방식으로 변경하면 B 인스턴스는 파괴되지만 새로운 인스턴스 생성되지 않습니다. A보다 null 종속성이 표시됩니다. 내가 맞습니까?
  3. StaticApplicationContextBeanFactoryPostProcessor 둘 다 런타임에서 bean 정의를 변경할 수 있습니다. 그러나 차이점은 무엇입니까, 찬성/반대입니까?

  4. [주요 질문] 왜 스프링에는 같은 목표를 달성하는 3 가지 메커니즘이 있습니다. AbstractApplicationContext#refresh(), StaticApplicationContextBeanFactoryPostProcessor 사이의 간단한 compoarison (또는 사용 예제)을 만들 수 있습니까?

답변

11

(아래 코드 참조) 안전한가요?

안전을 정의해야합니다. 이 매달려 자원을 피하기 위해, 실패 할 경우

AbstractApplicationContext#refresh() 메소드의 javadoc 상태

이 시작 방법이기 때문에, 그것은 이미 싱글을 만들었을 쳐부한다. 즉, 해당 메소드를 호출 한 후 을 호출하면 모두 의 모든 싱글 톤이 인스턴스화되어야합니다.

기본적으로 컨텍스트의 모든 빈은 삭제되고 모든 참조가 삭제되어 가비지 수집 대상이됩니다. 빈이 가지고있는 자원을 해제 할 수있는 적절한 f}을 가지고 있는지 확인해야합니다. There are different ways to do that

  • 클래스에 DisposableBean 인터페이스를 구현하게하십시오.
  • <bean> 또는 @Bean 정의에 destroy-method 속성을 추가하십시오.
  • @PreDestroy으로 주석을 달아주십시오.

refresh()은 일반적으로 ApplicationContext을 열심히 새로 고칩니다. 모든 빈을 즉시 다시 인스턴스화하십시오. 이런 일이 발생하는 동안 애플리케이션이 느려질 수 있습니다.

나는 StaticApplicationContext 또는 BeanPostProcessor 또는 BeanFactoryPostProcessor의 도움으로 런타임에 빈 정의 변화를 달성 할 수 있음을 읽은? 그래서 차이점은 무엇입니까?

StaticApplicationContext은 사용자가 직접 빈 정의를 등록하는 ApplicationContext 클래스 중 하나입니다. 귀하의 예제에서 bean 정의는 XML 파일에서 파싱되어 뒤에서 등록됩니다. StaticApplicationContext을 사용하면 registerBeanDefinition(..) 또는 다른 registerXxx() 메소드를 사용하여 Bean 정의를 명시 적으로 등록 할 수 있습니다.

BeanFactoryPostProcessorBeanFactory에 액세스 할 수 있으며 따라서 등록 된 모든 bean 정의가 사용됩니다. 따라서 원하는 모든 BeanDefinition을 검색하여 수정할 수 있습니다. BeanFactoryPostProcess#postProcessBeanFactory(..)를위한 Javadoc가

상태로 모든 bean 정의는로드 된 것입니다,하지만 콩 가 아직 인스턴스화이 없습니다. 따라서 bean을 열심히 초기화하는 경우에도 속성을 재정의하거나 추가 할 수 있습니다.

ApplicationContext 실제로 사용하기 전에 bean 정의를 변경할 수 있습니다.

마지막으로 BeanPostProcessor은 bean 정의를 변경하지 않습니다. BeanPostProcessor을 사용하여 Bean의 작성 방법을 변경할 수 있지만 기본 BeanDefinition은 그대로 유지됩니다. (실제 답 :보다 큰) 당신의 편집

내가 BeanPostProcess을 알고있는 것처럼

당신이 수정할 수 있도록 들어


이미 프록시와 객체를 래핑하여 런타임에 빈 인스턴스를 존재했다. 내가 맞습니까?

그것은 당신이 개체와 원하는 모든 것을 할 수있는, 단지 프록시에 아니다 : 등, 그것은 null 수 있도록, 다른 컨텍스트에 등록, 해당 속성을 수정 이것은 bean 정의 주위에 간다.

AbstractApplicationContext#refresh() 모든 싱글 톤 빈을 삭제하고 을 다시 만듭니다.

하지만 프로토 타입/사용자 정의 범위 정의를 bean으로 변경하고 싶습니까? 만약 내가 두 개의 bean을 가지고 있다면 : A와 B.는 B에 대한 참조를 가지고있다. 은 빈 정의를 변경하여 의 B 정의를 포함하지 않는다. B 인스턴스보다 B 인스턴스는 파괴되지만 새로운 인스턴스는 이다. 생성되지 않습니다. A보다 null 종속성이 생깁니다. 내가 맞습니까?

ApplicationContext에서 사용자는 bean 정의를 선언합니다. Bean 정의를 변경하려면 BeanFactoryPostProcessor으로 변경하거나 컨텍스트 구성에서 다르게 선언하십시오.

B bean 정의를 파기하면 A에 삽입 할 bean이 없으므로 Spring은 NoSuchBeanDefinitionException을 던집니다. 콩 주입은 명시 적으로 말하지 않는 한 null을 주입하지 않습니다.

StaticApplicationContextBeanFactoryPostProcessor 모두 변화 런타임에 빈 정의에 나를 수 있습니다. 하지만 차이점은 무엇입니까 찬성/반대입니까?

이 두 가지는 완전히 다른 용도로 사용됩니다. StaticApplicationContextApplicationContext 구현입니다. 여기에서 bean 정의를 선언한다. BeanFactoryPostProcessor은 구현하고자하는 조건에 따라 어떤 방식 으로든 이러한 bean 정의를 수정하는 역할을합니다.

왜 스프링에는 동일한 목표를 달성하는 3 가지 메커니즘이 있습니다. 을 AbstractApplicationContext#refresh(), StaticApplicationContextBeanFactoryPostProcessor 사이의 간단한 비교 (또는 사용 사례)로 만들 수 있습니까?

목표가 동일하지 않습니다. ApplicationContextBeanFactoryPostProcessor과 다르며 컨텍스트 수명주기에서 다른 시간에 재생됩니다 (이전 질문에서 사용한 멋진 그래프 참조).

사용 사례가 없습니다. 위의 각각이 무엇을 할 수 있는지 배우십시오. 특정 요구 사항을 얻을 때 적용 할시기를 알 수 있습니다.

+0

전 대답에 감사드립니다. 제 질문의 * EDIT * 섹션에서 질문에 답변 해 주시기 바랍니다. –

+0

@VolodymyrBakhmatiuk 내 편집을 참조하십시오. –

+0

많은 감사합니다! –