a3dsfcv
a3dsfcv

Reputation: 1274

Spring specify implementation in configuration

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

UPDATE 1

I've added @Profile("InMemory") to Configuration and activated that profile in properties. That gave no changes but looks more logical now

UPDATE 2

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

Answers (2)

a3dsfcv
a3dsfcv

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

MaxExplode
MaxExplode

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

Related Questions