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

  • корень
    • core (имеет класс TestingHandler, внедряет TestingRepository для сохранения данных)
    • persistence-api (с настраиваемым интерфейсом репозитория TestingRepository)
    • постоянная память (с абстрактным классом 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();
}

Вот подразумеваемый класс 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);
    }

}

У меня также есть класс бегуна, который вызывает метод-обработчик:

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

}

Есть указатели?

1
vikesh pandey 11 Апр 2019 в 15:47

2 ответа

Лучший ответ

Ваш 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 с превосходным ПРОЧИТАЙТЕ с другими полезными ссылками.

0
noiaverbale 11 Апр 2019 в 13:17

Мне кажется, что не только ваш 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....
}

}
0
João Mota 11 Апр 2019 в 13:21