CrudRepository внутри моей реализации репозитория - программирование
Подтвердить что ты не робот

CrudRepository внутри моей реализации репозитория

Я пытаюсь получить ссылку на мой интерфейс репозитория (UserRepository), который расширяет CrudRepository в моей пользовательской реализации (UserRepositoryExtensionImpl), чтобы получить доступ ко всем методам, предоставленным Spring JPA.

Расширение Crud:

@Repository
public interface UserRepository extends CrudRepository<User, String>, UserRepositoryExtension<RosterUser> {
    ...any custom spring JPA methods...
}

Интерфейс расширения:

@Repository
public interface UserRepositoryExtension <T> {
   public T put(T entity);
}

Пользовательская реализация:

public class UserRepositoryExtensionImpl implements UserRepositoryExtension<User> {

    UserRepository userRepository;

    @Autowired
    public UserRepositoryExtensionImpl(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public User put(User user) {
        System.out.println(user + "was put");
        // ...put logic here
        return null;
    }...
}

Однако я не могу ввести UserRepository, поскольку существует циклическая зависимость (учитывая, что UserRepository расширяет интерфейс, реализованный моим UserRepositoryImpl). Я получаю следующую ошибку:

org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name '    userRepositoryImpl': Requested bean is currently in creation: Is there an unresolvable circular     reference?

Возможно, но менее идеальным решением было бы ввести и EntityManager в UserRepositoryImp, но в этом случае у меня нет доступа к каким-либо из методов Spring JPA, предоставляемых CrudRepository, или любые дополнительные методы, которые я мог бы создать в UserRepository.

Любые предложения о том, как обойти это?

Любая помощь будет принята с благодарностью.

EDIT: Как упоминалось в ответе @shelley, я смог решить это, сделав 3 изменения:

  • Удаление @Repository из UserRepositoryExtensionImpl
  • Переименование UserRepositoryExtensionImpl на UserRepositoryImpl. По-видимому, это означает, что Spring знает о существовании реализации. См. Spring Doc
  • Удаление моего конструктора и перемещение поля @Autowired в поле UserRepository

УСПЕХ!

4b9b3361

Ответ 1

Для этого нужно изменить пару мелочей:

  • Удалите аннотацию @Repository из пользовательского интерфейса репозитория (UserRepositoryExtension).

  • Реализация пользовательского репозитория должна называться "<StandardRepository>Impl", а не "<CustomRepository>Impl". В вашем примере кода это должно быть UserRepositoryImpl вместо UserRepositoryExtensionImpl.

Ответ 2

Как указал лейплий, именование действительно важно, чтобы сделать работу автошины. В приведенном ниже примере я следую правильному стандарту именования для моего пользовательского интерфейса и его реализации. Но мой интерфейс, расширивший JpaRepository, назывался "ItemDao" вместо "ItemRepository", это привело к тому, что spring вообще игнорировал мою собственную реализацию...

OBS!!! Должен быть "ItemRepository"

@Repository
public interface ItemDao extends JpaRepository<Item, Long>, ItemRepositoryCustom {}

мой интерфейс

interface ItemRepositoryCustom {...}

мой класс реализации

class ItemRepositoryImpl implements ItemRepositoryCustom {...}

Если у кого-либо есть подобные проблемы, начните с использования стандарта именования, который используется в документации по spring по ссылке ниже.

http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations

Ответ 4

Я решил проблему, введя ApplicationContext и получив bean ленивым способом, используя applicationContext.getBean(UserRepository.class). Он работает таким образом.

Ответ 5

Я нашел способ, как сделать это без необходимости @Autowire:

public interface UserRepository extends 
    UserRepositoryBasic,
    UserRepositoryExtension 
{ 
}

public interface UserRepositoryBasic extends
    JpaRepository<User, String>
{
    // standard Spring Data methods, like findByLogin
}

public interface UserRepositoryExtension 
{
    public void customMethod();
}

public class UserRepositoryExtensionImpl implements
    UserRepositoryExtension 
{
    private final UserRepositoryBasic userRepositoryBasic;

    // constructor-based injection
    public UserRepositoryExtensionImpl(
        UserRepositoryBasic userRepositoryBasic)
    {
        this.userRepositoryBasic = userRepositoryBasic;
    }

    public void customMethod() 
    {
        // we can call all basic Spring Data methods using
        // userRepositoryBasic
    }
}

Ответ 6

Хорошо, в этом случае я предлагаю использовать аннотацию @Lazy.

public class MyCustomRepositoryImpl implements MyCustomRepository {

    @Lazy
    @Autowired
    private MyRepository myRepository;

    @Override
    public boolean customMethod() {
       return myRepository.count() > 0;
    }

}

С помощью параметра конструктора Spring пытается создать "базовый" класс репозитория, для которого требуется пользовательский репозиторий, для которого требуется "базовый" репозиторий - типичный случай с циклической зависимостью.

Без @Lazy но только с @Autowired он также не будет работать (будет проблема с фабричным компонентом для базового репо).

Я думаю, что в этом случае @Lazy - самое элегантное решение.