2014-11-14 7 views
0

Я использую Spring 4 через Spring Boot 1.1.8 и создал класс для кэширования некоторых данных. Класс полагается на дженерики, чтобы работать, но у меня возникают проблемы с Spring и аутоавтоматизация этого класса как компонента в другой службе.Spring 4 bean autowiring with generics

Я получаю ошибки как это:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [orm.repository.BaseRepository] is defined: expected single matching bean but found 2: dataTypeRepository,propertyNameRepository 

Класс в вопросе:

/** 
* The purpose of this class is to get data from a cache backed by a database 
* and if it does not exist to create it and insert into the database. 
*/ 
@Service 
public class CacheByName<TRepo extends BaseRepository, TItem extends BaseWithName> { 
    private final TRepo repo; 
    private final Class<TItem> itemClass; 
    private final Map<String, TItem> itemsCache; // TODO: change to better caching strategy 

    @Autowired 
    public CacheByName(TRepo repo, Class<TItem> itemClass) { 
     this.repo = repo; 
     this.itemClass = itemClass; 
     itemsCache = new HashMap(); 
    } 

    public TItem getCreateItem(String name) { 
     TItem item = null; 
     if(itemsCache.containsKey(name)) { 
      item = itemsCache.get(name); 
     } else { 
      // try and load from db 
      item = (TItem) repo.findByName(name); 
      if(item == null) { 
       try { 
        item = itemClass.newInstance(); 
        item.setName(name); 
        repo.saveAndFlush(item); 
       } catch (InstantiationException | IllegalAccessException ex) { 
        // TODO: log and handle better 
        return null; 
       } 

      } 
      itemsCache.put(name, item); 
     } 

     return item; 
    } 
} 

Класс BaseRepository расширяет JpaRepository следующим образом. Другие реальные репозитории расширяют этот.

@NoRepositoryBean 
public interface BaseRepository<T extends Object, ID extends Serializable> extends JpaRepository<T, ID> { 
    public T findByName(String name); 
} 

Класс BaseWithName является MappedSuperclass, который определяет свойство имя и геттеры/сеттеры для него. Другие более конкретные классы сущностей расширяют это.

Я пытаюсь ввести класс CacheByName в другую службу, например следующую. Обратите внимание, что я определяю фактическое хранилище и класс сущностей как дженерики в конструкторе:

@Service 
public class DataImporter extends BaseImporter { 
    private static final Logger log = LoggerFactory.getLogger(PropertyImporter.class); 
    private final PropertyNameRepository propertyNameRepo; 
    private final CacheByName<DataTypeRepository, DataType> dataTypeCache; 


    @Autowired 
    public PropertyImporter(RestTemplate restTemplateD5, 
          CacheByName<DataTypeRepository, DataType> dataTypeCache) { 
     super(restTemplateD5); 
     this.dataTypeCache = dataTypeCache; 
    } 

    . 
    . 
    . 
} 

Мой AppConfig.java выглядит следующим образом:

@Configuration 
@ComponentScan 
@EnableAutoConfiguration 
public class AppConfig { 
    @Value("${username}") 
    private String username; 
    @Value("${password}") 
    private String password; 

    @Bean 
    public RestTemplate restTemplateD5() { 
     return RestTemplateFactory.createWithHttpBasicAuth(username, password); 
    } 
} 

Я не смог найти много информации о создании бобы, которые используют дженерики. Я подозреваю, что мне нужно создать еще одно определение @Bean в моем AppConfig, но я не смог реализовать ничего, что сработало.

+0

Почему вы просто не usings пружины '@ поддержки Cacheable' вместо этого? Просто добавьте аннотацию и бинго, кеширование ... –

+0

Да, спасибо. Я планирую использовать это в будущем, но мой вопрос касается скорее создания экземпляра bean, а не аспекта кеширования. – Hamish

ответ

0

Поскольку BaseRepository также является общим типом, я думаю, вы пропустили, чтобы добавить общий тип там. Это должно помочь Spring найти правильный боб впрыснуть:

public class CacheByName<TRepo extends BaseRepository<TItem, ? extends Serializable>, TItem extends BaseWithName> 

Это должно также сделать бросок больше не нужен:

item = repo.findByName(name); 
Смежные вопросы