Reputation: 1274
I'm writing application using spring mvc/boot, and I have two storage implementations: database storage and in memory storage. My global idea is choose in configuration file what storage application should use.
My idea is
The thing is I don't know how to bind implementation and configuration.
I tried something like this:
@Configuration
public class InMemoryStorageConfig {
@Autowired
@Qualifier("inMemoryStorage")
private Storage storage;
@Bean
public Storage getStorage() {
return storage;
}
}
But I get an error, that 3 beans were found: 2 beans with dfferent implementation and the 3rd one - in config
I've added @Profile("InMemory")
to Configuration and activated that profile in properties. That gave no changes but looks more logical now
Full configuration:
@SpringBootApplication
@ImportResource("classpath:spring-config.xml")
public class Application {
public static void main(String... args) {
SpringApplication.run(Application.class, args);
}
}
@Service
public class WidgetService {
private WidgetCache widgetCache;
@Autowired
public WidgetService(WidgetCache widgetCache) {
this.widgetCache = widgetCache;
}
....
@Qualifier("databaseWidgetCache")
@Transactional
@Repository
public class DatabaseWidgetCache implements WidgetCache {
private WidgetRepository widgetRepository;
@Autowired
public DatabaseWidgetCache(WidgetRepository widgetRepository) {
this.widgetRepository = widgetRepository;
}
@Qualifier("inMemoryWidgetCache")
@Repository
public class InMemoryWidgetCache implements WidgetCache {
private WidgetLayersStorage widgetLayersStorage;
@Autowired
public InMemoryWidgetCache(WidgetLayersStorage widgetLayersStorage) {
this.widgetLayersStorage = widgetLayersStorage;
}
@Profile("InMemory")
@Configuration
public class InMemoryStorageConfig {
@Autowired
@Qualifier("inMemoryWidgetCache")
private WidgetCache widgetCache;
@Bean
public WidgetCache getWidgetCache() {
return widgetCache;
}
}
Stacktrace:
Parameter 0 of constructor in
com.widgets.service.widget.WidgetService required a single
bean, but 3 were found:
- inMemoryWidgetCache: defined in file [..../MemoryWidgetCache.class]
- databaseWidgetCache: defined in file [..../DatabaseWidgetCache.class]
- getWidgetCache: defined by method 'getWidgetCache' in class path resource
[......../InMemoryStorageConfig.class]
Action:
Consider marking one of the beans as @Primary, updating the consumer
to accept multiple beans, or using @Qualifier to identify the bean
that should be consumed
Upvotes: 1
Views: 871
Reputation: 1274
In order to specify implementation in Configuration class, you don't need "Qualifier" annotation, and configuration should be changed to:
@Profile("inMemoryStorage")
@Import(InMemoryWidgetCache.class)
@Configuration
public class InMemoryStorageConfig {
}
thus, by activating profile, you choose the desire implementation
Upvotes: 0
Reputation: 2007
Your WidgetService should be changed to
@Service
public class WidgetService {
private WidgetCache widgetCache;
/** or
private List<WidgetCache> widgetCaches;
public WidgetService(List<WidgetCache> widgetCaches) {
this.widgetCaches = widgetCaches;
}
*/
public WidgetService(@Qualifier(<desired impl>) WidgetCache widgetCache) {
this.widgetCache = widgetCache;
}
}
and need to annotate your InMemoryWidgetCache
and DatabaseWidgetCache
with @Qualifier
annotation. since you are using default convention.
and please remove
@Bean
public WidgetCache getWidgetCache() {
return widgetCache;
}
i don't see a real use there
Upvotes: 1