根据类型参数自动装配CrudRepository

时间:2018-09-19 13:18:51

标签: java spring spring-boot spring-data-jpa

我想在抽象的父类中自动连接CrudRespository<Type,Key>,然后将其与子类一起使用。错误告诉我:

java.lang.IllegalStateException: Failed to load ApplicationContext
[...]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'accountExtractor': Unsatisfied dependency expressed through field 'repository'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.data.repository.CrudRepository<com.finnwa.adwords.adconnect.Account, java.lang.Long>' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

定义依赖项的抽象父级。

@Component
public abstract class Extractor<T,KEY> {

    @Autowired
    protected CrudRepository<T,KEY> repository;
   // some business logic
}

提供参数的子类。

@Component
class AccountExtractor extends Extractor<Account, Long>{
    // some config
}

其他可能相关的类:

public interface AccountRepository extends CrudRepository<Account, Long>{}

@SpringBootApplication
@EnableJpaRepositories(basePackages = "package.my")
public class Application {
    public static void main(String[] args) {
         SpringApplication.run(Application.class);
    }
}

我从其他问题中学到,父类中的依赖关系可能不是私有的。所以我保护了它。我想念什么吗?

编辑:Paul Janssens和M. Deinum发布了一些不错的解决方法。但是为什么不起作用呢?怎么了?

3 个答案:

答案 0 :(得分:1)

对于初学者,我建议不要使用字段注入,而应使用构造函数注入。我还建议使用特定类型,因为泛型的更改是删除了类型信息。

我可能会做

public abstract class Extractor<T,KEY> {

  private final CrudRepository<T,KEY> repository;

  protected Extractor(CrudRepository<T, KEY> repository) {
    this.repository=repository;
  }
}

然后在您的特定类中使用AccountRepository并将其传递给超类。

@Component
class AccountExtractor extends Extractor<Account, Long>{

  AccountExtractor(AccountRepository repository) {
    super(repository);
  }
}

这样,在您的超类和方法中,您仍然可以使用基本类型CrudRepository。另外的好处是,您现在可以非常轻松地为AcountExtractor编写单元测试,并简单地模拟AccountRepository,而不必引导Spring Boot应用程序。 (我知道您可以使用@DataJpaTest,但尽管如此,简单的模拟还是要更快的)。

答案 1 :(得分:1)

只使用抽象方法并在子类中执行接线

public abstract CrudRepository<T,KEY> getRepository();

...

FooRepository implements CrudRepository<Foo,Integer>

...

@Autowired
protected FooRepository repository;

@Override
public CrudRepository<Foo,Integer> getRepository() {
    return repository;
}

答案 2 :(得分:-1)

我会说AccountRepository缺少“魔术注释”:

@Repository // This tells Spring Data to actually create a "standard" repository instance for us
public interface AccountRepository extends CrudRepository<Account, Long>{}