Reputation: 12871
My situation is that I have a properties-file to configure an unknown number of beans:
rssfeed.source[0]=http://feed.com/rss-news.xml
rssfeed.title[0]=Sample feed #1
rssfeed.source[1]=http://feed.com/rss-news2.xml
rssfeed.title[1]=Sample feed #2
:
I have a configuration class to read those properties:
@Configuration
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "rssfeed", locations = "classpath:/config/rssfeed.properties")
public class RssConfig {
private List<String> source = new ArrayList<String>();
private List<String> title = new ArrayList<String>();
public List<String> getSource() {
return source;
}
public List<String> getTitle() {
return title;
}
@PostConstruct
public void postConstruct() {
}
}
This is working nicely. However, now I want to create beans based on that. What I've tried so far is
add @Bean
-methods and call them from postConstruct()
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public SourcePollingChannelAdapter createFeedChannelAdapter(int id, String url) {
SourcePollingChannelAdapter channelAdapter = new SourcePollingChannelAdapter();
channelAdapter.setApplicationContext(applicationContext);
channelAdapter.setBeanName("feedChannelAdapter" + id);
channelAdapter.setSource(createMessageSource(id, url));
return channelAdapter;
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public FeedEntryMessageSource createMessageSource(int id, String url) {
try {
FeedEntryMessageSource messageSource = new FeedEntryMessageSource(new URL(url), "");
messageSource.setApplicationContext(applicationContext);
messageSource.setBeanName("feedChannelAdapter" + id + ".source");
return messageSource;
} catch (Throwable e) {
Utility.throwAsUncheckedException(e);
return null;
}
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public QueueChannel createFeedChannel(int id, String url) {
QueueChannel channel = new QueueChannel();
channel.setApplicationContext(applicationContext);
channel.setBeanName("feedChannel" + id);
return channel;
}
@PostConstruct
public void postConstruct() {
for (int x = 0; x < source.size(); x++) {
createFeedChannelAdapter(x, source.get(x));
}
}
However, Spring tries to autowire the parameters to those methods rather than using the parameters I provided in postConstruct()
.
a BeanFactoryPostProcessor
or a BeanDefinitionRegistryPostProcessor
. However, here I don't have access to the properties-file or the RssConfig
-bean from above as it's called too early in the lifecycle.
What do I need to do generate those dynamic number of beans? I'm probably just a tiny little step away... I prefer a Java configuration-solution over an XML-solution.
Upvotes: 3
Views: 1933
Reputation: 58124
You need to register the bean definitions (not call @Bean
methods), so BeanDefinitionRegistryPostProcessor
or ImportBeanDefinitionRegistrar
are the best ways to do that currently. You can grab the properties file and bind to it using PropertiesConfigurationFactory
(in Spring Boot) instead of using @ConfigurationProperties
, or maybe you could use a parent context or a standalone SpringApplication
to create and bind your RssConfig
inside your bean definition registration code.
Upvotes: 4