我的使用情况如下:
我目前正在开发一个应用程序,其中有一个EventModule负责触发各种事件。其中之一是TimeEvent。这些时间事件应该每秒钟触发一次。当我的应用程序在运行时,还应该能够添加对新事件的支持。为了满足后一要求,我使用OSGI。
对于生成时间事件本身,我发现Spring已经为我提供了这样的功能,即通过在将周期性调用的方法上放置@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
时,在我的 BundleActivator
的 start(BundleContext)
方法中创建此类的实例,因此不考虑使用 @ Component
注释。这就是我遇到问题的地方。我了解到可以通过使用
BeanFactoryPostProcessor
在Spring应用程序上下文中自己注入bean,这正是我所做的,结果如下所示:/**
* 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 );
}
}
在这里的问题是,每当我使用
createBean
方法创建一个TimeEventGenerator
(参见第一个代码片段)时,testSchedule()
方法从未被调用,而我原本期望它会被调用,因为该bean由Spring管理。编辑:我忘记添加了,我也尝试过使用两个GenericBeanDefinition的子类,即ScannedGenericBeanDefinition和AnnotatedGenericBeanDefinition,但也都没有成功。
RuntimeBeanFactory
扩展ScheduledAnnotationBeanPostProcessor
并在从应用程序上下文中检索到新创建的 bean 之后调用afterSingletonsInstantiated
方法:.... public T createBean( Class aBeanClass, String aBeanName ) throws IOException {
// previous code from the original post untouched
// ....
T bean = applicationContext.getBean( aBeanClass ); afterSingletonInstantiated(); return bean; } - Kristof P.