I have several similar sets of beans. For example, I could have a connection to database, monitoring for that database, and DAO for that database, thread pool for that database and so on. And I'd like to instantiate this set of beans several times in the same context with slightly different properties (eg with different host name). I'd like to have something like this:
abstract class ContextTemplate {
abstract String dbHost();
@Bean
DataSource dataSource() { return new DataSourceImpl(dbHost()); }
@Bean
DbMonitoring dbMonitoring() { return new DbMonitoring(dataSource()); }}
// and ten more db-specific beans
}
@Configuration(prefix = "primary-")
class PrimaryDbContext extends ContextTemplate {
@Override
String dbHost() { return "primary.host"; }
}
@Configuration(prefix = "slow-reqs-")
class SlowRequestsContext extends ContextTemplate {
@Override
String dbHost() { return "slow.requests.host"; }
}
@Configuration
@Import({
PrimaryContext.class,
SlowRequestsContext.class,
})
class MyContext {
}
With this imaginary configuration instantiated I'd like to have a single context with beans primary-dataSource
, primary-monitoring
, slow-reqs-dataSource
, slow-reqs-monitoring
.
The point is that each of PrimaryDbContext
and SlowRequestsContext
should emit several very similar bean definitions in one resuling application context.
Is something like this possible with Spring?
Edit: created a feature request in the Spring tracker .
I know this solution is not looking like your example. But you can't change bean names with any other ways, only manually. Create custom factory post processor:
public class DbRegistryPostProcessor implements BeanFactoryPostProcessor{
private String hostName;
private String prefix;
public BeanFactoryPostProcessor(Strin prefix, String hostName){
this.prefix = prefix;
this.hostName = hostName;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
factory.registerSingleton(prefix+"dataSource", dataSource());
factory.registerSingleton(prefix+"dbMonitoring", dbMonitoring());
}
DataSource dataSource() { return new DataSourceImpl(hostName); }
DbMonitoring dbMonitoring() { return new DbMonitoring(dataSource()); }}
// and ten more db-specific beans
}
And register post-processors in configuration:
@Configuration
public class MyContext {
@Bean
public DbRegistryPostProcessor primaryDbProcessor(){
return new DbRegistryPostProcessor("primary-", "primary.host");
}
@Bean
public DbRegistryPostProcessor secondaryDbProcessor(){
return new DbRegistryPostProcessor("secondary-", "secondary.host");
}
}
Of course, with this approach your beans will not be processed by other post processors (for example with PropertySourcesPlaceholderConfigurer
). If you need beans to be processed by other post processors, you can implement custom BeanDefinitionRegistryPostProcessor
instead of BeanFactoryPostProcessor
.
Dynamically you can switch between different data sources by maintaining a flag that you can change by hitting a Servlet that sets the flag in cookie or application context scope.
Just register one bean of ContextTemplate
that internally keeps two ContextTemplate
.
ContextTemplate
onceFor example:
@Component
public class MyContextTemplate implements InitializingBean, ContextTemplate {
private ContextTemplate primary;
private ContextTemplate secondary;
@Override
public void afterPropertiesSet() {
// initialize primary and secondary ContextTemplate
// you can initialize them in default constructor of this class also
}
public DataSource dataSource() {
if(flat-set) {
return primary.dataSource();
}
return secondary.dataSource();
}
public DbMonitoring dbMonitoring() {
if(flat-set) {
return primary.dbMonitoring();
}
return secondary.dbMonitoring();
}
// implement other methods
}
You can register multiple bean of ContextTemplate
also and mark MyContextTemplate
as primary bean to resolve the auto-wiring conflict issue.
Think about some of design patterns that can fit as per your requirement:
A snapshot of State pattern:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.