2014-11-14 3 views
0

스프링 부트 1.1.8을 통해 스프링 4를 사용 중이며 일부 데이터를 캐시 할 클래스를 만들었습니다. 이 클래스는 제네릭을 사용하여 작동하지만 Spring에 문제가있어이 클래스를 다른 서비스의 bean으로 autowiring합니다.제네릭을 사용하는 스프링 4 빈 자동 와이어링

나는 다음과 같은 오류를 얻을 :

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은 이름 속성과 getters/setters를 정의하는 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); 
    } 
} 

내가 많은 정보를 찾을 수 없어 제네릭을 사용하는 빈을 만드는 방법. 내 AppConfig에 또 다른 @Bean 정의를 만들어야한다고 생각하는데, 제대로 된 것을 구현할 수 없었다.

+0

가 왜 당신은 단순히 대신 Cacheable' 지원 @ 스프링을'using이됩니다

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

이 또한 캐스트가 더 이상 필요하지 않습니다해야합니까? 어노테이션과 빙고를 추가하여 캐싱을하면됩니다. –

+0

예. 감사합니다. 미래에 사용할 계획이지만 제 질문은 캐싱 측면보다는 빈 인스턴스화에 관한 것입니다. – Hamish

답변

0

BaseRepository도 제네릭 유형이므로 제네릭 유형을 추가하지 않으 셨습니다. 즉 봄이 적절한 빈을 주입하기 위해 찾아 도움 :

item = repo.findByName(name); 
관련 문제