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
УСПЕХ!
Ответы
Ответ 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
Ответ 3
Существует четко определенный способ создания пользовательских реализаций репозитория в Spring данных JPA, за которыми вы должны следовать. В основном вам нужно расширить CrudRepository
, поэтому вам не нужно вставлять его экземпляр в вашу пользовательскую реализацию.
Ответ 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
- самое элегантное решение.