2014-11-07 5 views
3

내 사용 사례는 다음과 같은 : 나는 현재 모든 종류의 이벤트를 발사 담당하는 EventModule이있는 응용 프로그램을 개발하고 있어요사용 @Scheduled 주석은 런타임에서 스프링 빈을 생성

. 이러한 이벤트 중 하나가 TimeEvent입니다. 이 시간 이벤트는 매 초마다 발생해야합니다. 또한 응용 프로그램이 시작되어 실행 중일 때 새 이벤트에 대한 지원을 추가 할 수 있어야합니다. 후자의 요구 사항에 대해서는 OSGI를 사용하고 있습니다.

시간 이벤트 자체를 생성하기 위해 스프링이 이미 저의 기능을 제공한다는 것을 알았습니다. 즉, 주기적으로 (매초마다) 호출 할 메서드에 @Scheduled 주석을 삽입하는 것으로 나타났습니다.

/** 
* Generator class that periodically generates {@link TimeEvent}s. 
*/ 
@Component 
@EnableScheduling 
public class TimeEventGenerator { 

    @Scheduled(cron = "*/1 * * * * ?") 
    public void testSchedule() { 
    // fire a time event 
    } 

} 

이 잘 작동하고 이벤트 초마다 해고 :

그래서 그러므로 나는이 코드를 가지고 있었다. 그러나이 경우 시작시 TimeEventGenerator 클래스를 인스턴스화해야합니다 (@Component이라는 주석이 있기 때문에). 내 유스 케이스, 즉 OSGI 부분에서는 TimeEvents에 대한 지원을 꽂기로 결정할 때마다이 start(BundleContext) 메서드에서 내 BundleActivator 메서드로이 클래스의 인스턴스를 만들 수 있어야합니다. 따라서 @Component 주석을 사용하는 것은 옵션이 아닙니다.

일부 문제가있는 부분입니다. 나는 내가 한 정확히 무엇이다하는 BeanFactoryPostProcessor를 사용하여 스프링 애플리케이션 컨텍스트에 콩에게 자신을 주입 할 수 있다는 것을 배웠이 다음 코드 결과 :

/** 
* Class that allows to add spring beans to a running application context. 
*/ 
@Component 
public class RuntimeBeanFactory implements ApplicationContextAware, 
            BeanFactoryPostProcessor { 

    private ApplicationContext applicationContext; 
    private ConfigurableListableBeanFactory beanFactory; 

    @Override 
    @Autowired 
    public void setApplicationContext(ApplicationContext aApplicationContext) throws  BeansException { 
    applicationContext = aApplicationContext; 
    } 

    @Override 
    @Autowired 
    public void postProcessBeanFactory(ConfigurableListableBeanFactory aBeanFactory)  throws BeansException { 
    beanFactory = aBeanFactory; 
    } 

    public <T> T createBean(Class<T> aBeanClass, String aBeanName) throws IOException { 
    BeanDefinitionRegistry registry = ((BeanDefinitionRegistry) beanFactory); 

    GenericBeanDefinition beanDefinition = new GenericBeanDefinition();  
    beanDefinition.setBeanClass(aBeanClass); 
    beanDefinition.setLazyInit(false); 
    beanDefinition.setAbstract(false); 
    beanDefinition.setAutowireCandidate(true); 

    if (!registry.isBeanNameInUse(aBeanName)) { 
     registry.registerBeanDefinition(aBeanName, beanDefinition); 
    } 

    return applicationContext.getBean(aBeanClass); 
    } 

} 

여기에 문제가 있음을 내가 만들 때마다 TimeEventGenerator (예를 들어 createBean 메서드를 사용하면 콩이 봄에 의해 관리되기 때문에 testSchedule() 메서드는 호출되지 않습니다.

편집 : 나는 또한 위의 코드를 두 가지 하위 클래스 인 GenericBeanDefinition, 즉 ScannedGenericBeanDefinition과 AnnotatedGenericBeanDefinition으로 성공하지 못했다고 덧붙였다.

답변

1

Spring 설명서를 보면 GenericBeanDefinition 대신 AnnotatedGenericBeanDefinition을 시도해야한다고 생각합니다. here 문서를 참조하십시오.

편집 ScheduledAnnotationBeanPostProcessor 코드를보고 내 특수 효과가 처리되고있었습니다. 포스트 프로세서가 예약 된 작업을 인식하더라도 작업 실행자와 작업을 한 번만 예약한다는 문제가있었습니다. 스케쥴 된 클래스를 등록 할 때까지 이미 발생 했었습니다. 호출되지 않았습니다. 새로 고침 이벤트를 사후 프로세서로 전달하면 일정이 잡히지 만 다른 모든 작업도 일정을 다시 잡았습니다. 코드 (적어도 Spring 3.2에서)를 보면서, 당신이하고 싶은 것은 주석을 사용해서는 불가능합니다. 사용자 정의 주석 프로세서를 생성하고 작업 실행 프로그램에 작업을 등록 할 수 있습니다.

+0

오 예, 저도 시도했습니다. 내 질문에 그것을 추가하는 것을 잊었다. 나는 어느 쪽도 일하지 않았다. 원래 질문에 추가하겠습니다. –

+0

귀하의 편집은 실제로 그것을 해결하는 데 도움이되었습니다! .... 공공 T createBean (클래스 aBeanClass, 문자열 aBeanName : 내가 한 것은'RuntimeBeanFactory'가'ScheduledAnnotationBeanPostProcessor'을 확장하고 응용 프로그램 컨텍스트에서 새로 만든 빈을 검색 _after_은'afterSingletonsInstantiated' 메소드를 호출했다) IOException을 던졌습니다. { // 원래 게시물의 이전 코드는 그대로 유지 // .... T bean = applicationContext.getBean (aBeanClass); afterSingletonInstantiated(); return bean; } –

0

TimeEventGenerator를 켜고 끄기 만하면 간단히 별도의 번들에 넣고 번들을 시작하고 중지하여 켜고 끄기 만하면됩니다.

관련 문제