Я использую 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, но я не смог реализовать ничего, что сработало.
Почему вы просто не usings пружины '@ поддержки Cacheable' вместо этого? Просто добавьте аннотацию и бинго, кеширование ... –
Да, спасибо. Я планирую использовать это в будущем, но мой вопрос касается скорее создания экземпляра bean, а не аспекта кеширования. – Hamish