Spring Data:抽象基础服务中的JPA存储库,用于调用带有规范的findAll

时间:2016-10-27 17:08:02

标签: java spring spring-boot spring-data repository-pattern

我希望了解Generic Repository模式。我有一个通用服务接口,它由抽象服务实现,由所有服务实现扩展。我想确保所有CRUD操作和按标准/规范搜索都在抽象服务中进行。

我的所有存储库都是扩展JpaRepository和JpaSpecificationExecutor的接口。但是,我无法在抽象服务中使用自动装配的存储库执行findAll(规范,可分页)。

我应该对结构做出哪些更改,以便我可以利用JpaSpecificationExecutor的方法?

服务接口:

public interface GenericFoo<T, S> {
     public List<T> search(S criteria, Pageable pageable) {
}

摘要服务:

public abstract class Foo<T, S> implements GenericFoo<T, S> {
    @Autowired
    private JpaRepository<T, Long> repository;

    public List<T> search(S criteria, Pageable pageable) {
         //throws compilation error
         repository.findAll(getSpecification(criteria), pageable);
    }

    protected abstract Specification<T> getSpecification(S criteria);
}

ServiceImpl:

@Component
@Transactional
public class BarServiceImpl extends Foo<Bar, BarSearchCriteria> implements GenericFoo {

    protected Specification<Bar> getSpecification(BarSearchCriteria criteria) {
        //implementation to be filled for each service
        return null;
    }  
}

存储库:

public interface BarRepository extends JpaRepository<Bar, Long>, JpaSpecificationExecutor<Bar> {
}

修改 我也尝试了以下操作,虽然编译错误消失了,但由于自动装配异常,应用程序仍然无法启动。

SimpleJpaRepository:

public interface SimpleRepository<T> extends JpaRepository<T, Long>, JpaSpecificationExecutor<T> {
}

BaseService:

public abstract class BaseService<T, S> implements GenericService<T, S> {
    @Autowired
    private SimpleJpaRepository<T, Long> simpleJpaRepository;

    public List<T> search(S criteria, Pageable pageable) {
        repository.findAll(getSpecification(criteria), pageable);
    }

    protected abstract Specification<T> getSpecification(S criteria);
}

存储库:

public interface BarRepository extends SimpleJpaRepository<Bar, Long> {
}

堆栈跟踪:

Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.data.jpa.repository.support.SimpleJpaRepository com.foopackage.barpackage.services.BaseService.simpleJpaRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.data.jpa.repository.support.SimpleJpaRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573) ~[spring-beans-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ~[spring-beans-4.2.8.RELEASE.jar:4.2.8.RELEASE]
... 22 common frames omitted
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.data.jpa.repository.support.SimpleJpaRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1380) ~[spring-beans-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1126) ~[spring-beans-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1021) ~[spring-beans-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545) ~[spring-beans-4.2.8.RELEASE.jar:4.2.8.RELEASE]
... 24 common frames omitted

2 个答案:

答案 0 :(得分:0)

  

我应该对结构做出哪些更改,以便我可以利用JpaSpecificationExecutor的方法?

创建和使用这样的中间界面应该可以解决问题:

public interface RepositoryWithExecutor<T> extends JpaRepository<T, Long>, JpaSpecificationExecutor<Bar> {}

现在您的BarRepository只是扩展RepositoryWithExecutor<Bar>

Foo<T>的存储库也应该是RepositoryWithExecutor<T>

已更新以回答更改后的问题

您正尝试自动装配SimpleJpaRepository<T, Long>类型的字段,但您ApplicationContext知道的所有字段都是BarRepository SimpleJpaRepository<Bar, Long>

您需要SimpleJpaRepository<T, Long>的通用实现,或者您必须创建BaseService的专用版本,T专门针对Bar并引用该专用版本。< / p>

旁注:我不认为你实际上正在显示你正在使用的代码,因为BaseService是抽象的,Spring不应该尝试实例化它。

答案 1 :(得分:0)

尝试这个:

 @Autowired
 private SimpleJpaRepository<T> simpleJpaRepository;

只需删除SimpeJpaRepository接口中的Long参数即可。