Почему пружинные репозитории jpa только для интерфейсов? - PullRequest
0 голосов
/ 11 апреля 2019

Я настраиваю многомодульный подпружиненный проект, имеющий следующую структуру:

  • root
    • core (с классом TestingHandler, добавляющим TestingRepository для сохранения данных)
    • persistence-api (с пользовательским интерфейсом хранилища TestingRepository)
    • persistence-memory (с абстрактным классом MemoryTestingRepository, расширяющим как TestingRepository, так и JpaRepository)
    • main (с точкой входа приложения ибегун, который вызывает TestingHandler для сохранения данных)

Я пытаюсь создать простое приложение с весенней загрузкой, которое сохранит пример записи в своей 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.

Что мне не хватает?

Я пробовал следующее:

  • Не используется иерархия репозитория.Просто с помощью одного интерфейса, который расширяет JpaRepository, и он работает, но у меня должна быть иерархия интерфейса из-за пользовательских методов и необходимости поддержки нескольких реализаций БД в будущем.
  • попытался использовать MemoryRepository непосредственно в TestingHandler, неРабота.Если я преобразовываю MemoryRepository в интерфейс (и избавляюсь от пользовательских методов), это работает.но, как я уже говорил, мне нужен собственный метод и поддержка иерархии интерфейса для поддержки унаследованного кода.
  • много пытался играть с аннотациями, такими как @EnableJpaRepositories, @ComponentScan и т. д., без помощи.
  • Testing.java - довольно стандартный POJO с аннотацией @Entity и @Id, очень простой.

Вот класс Handler:

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();
}

Вот класс impl TestingRepository:

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, который вызывает метод обработчика:

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 ]

0 голосов
/ 11 апреля 2019

Ваш 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 с отличным README с другими полезными ссылками.

0 голосов
/ 11 апреля 2019

мне кажется, что не только ваш MemoryTestingRepository не реализует интерфейс TestingRepository, но и является абстрактным, что меня немного смущает.Это реальный код или вы допустили ошибку при публикации?Если это так, то ответ может заключаться в том, что Spring может иметь проблемы с созданием bean-компонента из абстрактного класса.

Проверьте документацию 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....
}

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...