当前位置: 首页 > 知识库问答 >
问题:

为什么Spring data jpa存储库只强制接口?

贝研
2023-03-14

我正在建立一个多模块的spring-boot项目,其结构如下:

    • 核心(具有类TestingHandler,注入TestingRepository以保存数据)
    • 持久性api(具有自定义存储库接口TestingRepository)
    • 持久性内存(具有扩展TestingRepository和JpaRepository的MemoryTestingReppository抽象类)
    • main(具有应用程序的入口点和调用TestingHandler以保存数据的运行程序)

    我试图构建一个简单的spring boot应用程序,它将在h2 in-mem db中保存一个样本记录。但是我一直得到下面的错误:

    The injection point has the following annotations:
        - @org.springframework.beans.factory.annotation.Autowired(required=true)
    
    
    Action:
    
    Consider defining a bean of type 'com.****.***.services.testing.persistence.memory.MemoryTestingRepository' in your configuration.
    

    我错过了什么?

    我试过以下方法:

    • 不使用存储库层次结构。只使用一个扩展<code>JpaRepository
    • 尝试在TestingHandler中直接使用MemoryRepository,但无效。如果我将MemoryRepository转换为接口(并去掉自定义方法),它就会工作。但正如我提到的,我需要有自定义方法,并且必须支持接口层次结构,以支持遗留代码
    • 尝试使用@EnableJpaRepositories、@ComponentScan等注释,但没有帮助
    • 测试。java是非常标准的POJO,带有@Entity和@Id注释,非常简单

    下面是处理程序类:

    package com.***.**.services.testing.core;
    
    @Service
    public class TestingHandler {
    
        @Autowired
        private TestingRepository testingRepository;
    
        @NotNull
        public Testing create(@NotNull final TestingDto testingDto) {
            Testing testing = new Testing("123", testingDto.getName(), testingDto.getDescription(), testingDto.Key(), testingDto.getVersion());
            testingRepository.create(testing);
            return testing;
        }
    }
    

    注意,它正在注入接口TestingRepository。

    以下是TestingRepository接口(简单明了):

    package com.***.**.services.testing.persistence.api;
    
    @Repository
    public interface TestingRepository {
      void create();
      void findByCustomAttr();
    }
    

    下面是 TestingRepository 的 impl 类:

    package com.***.**.services.testing.persistence.memory;
    
    @Repository
    public abstract class MemoryTestingRepository implements JpaRepository<Testing, Integer>, TestingRepository {
     @Override
        public void create(@NotNull Testing testing) {
            save(testing); //the real jpa method called.
        }
    
    @Override
    public void findByCustomAttr(){
    //some impl....
    }
    
    }
    
    

    最后,主类如下所示:

    package com.***.**.services.testing.main;
    @SpringBootApplication(scanBasePackages = "com.***.**.services.testing")
    @EnableJpaRepositories("com.***.**.services.testing.persistence")
    @EntityScan(basePackages = {"com.***.**.services.testing.persistence"})
    public class TestingApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(TestingApplication.class, args);
        }
    
    }
    

    我还有一个runner类,它调用handler方法:

    package com.***.**.services.testing.main;
    
    @Component
    public class TestingService implements CommandLineRunner {
    
        @Autowired
        private TestingHandler testingHandler;
    
        @Override
    
        public void run(final String... args) throws Exception {
            test();
        }
    
    
        public void test() {
            testingHandler.create(new TestingDto("name", "desc", "some_mapping_id", Version.create()));
        }
    
    }
    

    有什么线索吗?

共有2个答案

夹谷俊远
2023-03-14

在我看来,不仅你的MemoryTestingRepository没有实现TestingRepository接口,而且是抽象的,这对我来说有点令人困惑。这是实际的代码,还是您在发布时犯了一些编辑错误?如果是这样,那么答案可能是Spring可能难以从抽象类中创建豆子。

查看文档https://docs . spring . io/spring-data/JPA/docs/current/reference/html/# repositories . single-repository-behavior,因为它解释了如何设置自定义存储库实现

编辑:根据您的评论和更新,我现在了解您的问题。

您想要的是让您的具体存储库扩展SimplaJpaRepository,以便您的实现可以访问JpaRepository的保存方法。

查看https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.customize-base-repository中的示例

您的存储库看起来像这样

package com.***.**.services.testing.persistence.memory;

@Repository
public class MemoryTestingRepository extends SimpleJpaRepository<Testing, Integer> implements TestingRepository {
 @Override
    public void create(@NotNull Testing testing) {
        save(testing); //the real jpa method called.
    }

@Override
public void findByCustomAttr(){
//some impl....
}

}
范甫
2023-03-14

你的 MemoryTestingRepository抽象的,因此它不能被 Spring 实例化。此外,存储库接口由Spring Data Jpa管理,您不应该在核心模块中具有这种依赖关系。

根据我在多模块项目中的经验(我承认很少),我目前在我的核心模块中为每个数据提供者请求创建SAM接口。然后在我的数据提供程序模块中的具体数据提供程序类中实现这些接口,注入所需的JpaRepository。

在您的情况下,这意味着:

核心模块:

@Service
public class TestingHandler {

    @Autowired
    private TestingCreator testingCreator;

    @NotNull
    public Testing create(@NotNull final TestingDto testingDto) {
        Testing testing = ...;
        testingCreator.createTesting(testing);
        return testing;
    }

}
public interface TestingCreator {

    void createTesting(Testing testing);

}

持久性模块

@Repository
public class TestingDataprovider implements TestingCreator /*, ...other interfaces from core module*/ {

    @Autowired
    private TestingRepository testingRepository;

    @Override
    public void createTesting(Testing testing) {
        testingRepository.save(testing);
    }

    // other methods like findByCustomAttr

}
public interface TestingRepository extends JpaRepository<Testing, Integer> {
    // custom methods
}

通过这种方式,您还可以将核心实体与持久性实体分离。

作为参考,我找到的最有用的指南是这个github资源库,其中有一个精彩的自述文件和其他有用的链接。

 类似资料:
  • 在我的springbootapp中,我有以下存储库:- 当我运行这个应用程序时。我收到了这个错误:- 启动ApplicationContext时出错。要显示条件报告,请在启用“调试”的情况下重新运行应用程序。2020-12-24 21:09:15 - 应用程序启动失败 说明: com中构造函数的参数0。如何使用Java。演示。存储库。RevisionRepository需要“org”类型的bean

  • 我使用artifactory(OSS 5.1.3)作为通用的构建依赖缓存。我注意到,在存储库浏览器中,每个远程存储库都有一个附加了缓存的第二个条目。例如:“jcenter”和“jcenter缓存”。 自动创建缓存条目。在我向缓存中添加了一个通用的“gradle distributions”存储库之后https://services.gradle.org/distributions/,我发现我在树中

  • 启动ApplicationContext时出错。若要显示条件报告,请在启用“调试”的情况下重新运行应用程序。2020-06-19 21:37:34.254错误11296---[restartedMain]O.S.Boot.SpringApplication:应用程序运行失败 输入图像描述这里输入图像描述

  • 问题内容: 我正在尝试使用GIT插件Jenkins拉出GIT的代码形式,并且该作业正在从属计算机上运行。 系统有 在系统中没有定义。 每当我在计算机上本地执行git clone时,它都能完美运行,但是从Jenkins那里我并没有成功。 它抛出以下错误: 是因为系统试图设置系统中不存在的http代理? 如果是,该如何预防? 或者,还有其他我想念的东西吗? 问题答案: 原来这是一个代理问题。 使用Je

  • 我正在使用100个实体(使用JHipster)设置一个新的Spring Boot API,我的问题是:鉴于我有一组存储库层方法,我希望我的所有存储库都能够调用这些方法。 我已经尝试制作所有接口来扩展('RepositoryQuery'是我默认的自定义接口名称后缀),然后使用特定于实体的类。请注意,所有的类扩展了一个泛型实现类,名为。 请注意,给定正则表达式中的“.*”代表我的持久实体集中的任何实体

  • 在第一次评估Artifactory之后,我发现在进行初始设置并选择Maven和Gradle集成时,它为我创建了两组存储库,这让我感到困惑 平台-gradle-dev-local 平台-分级-发布-本地 平台-libs-release-local 平台-libs-snapshot-local 有什么理由使用两个gradle repos,或者我可以对所有构建都使用标准的Maven repos吗?Gra