Обновлять: ниже используется Spring Boot 2.1.0
У меня есть репозиторий Spring Data, и я пытаюсь предоставить ему некоторые настраиваемые функции, следуя пример фрагментов из документации.
Итак, я добавил в репозиторий дополнительный интерфейс:
public interface UserRepository extends JpaRepository<User, Long>, UserExtraLogic {
User findByFirstNameAndLastName(String firstName, String lastName);
}
с этим настраиваемым интерфейсом:
interface UserExtraLogic {
void ensureHasAccess();
}
и его реализация:
class UserExtraLogicImpl implements UserExtraLogic {
public void ensureHasAccess() {
}
}
Проблема в том, что я хотел бы иметь возможность использовать свои репозитории внутри UserExtraLogicImpl, чтобы я мог повторно использовать методы запросов, такие как findByFirstNameAndLastName, без необходимости писать их самостоятельно с помощью EntityManager. Итак, я попробовал это:
class UserExrtaLogicImpl implements UserExtraLogic {
@Autowired
private UserRepository userRepository;
}
Но тогда приложение не запускается. Я получаю исключение NullPointerException, но я думаю, что Spring просто входит в цикл, пытаясь разрешить эти зависимости.
Возможно ли то, что я пытаюсь сделать? Есть другой способ сделать это?
Привет, Микаэль, трассировка стека слишком длинная и не соответствует поставленному вопросу. Я не добавил аннотацию @Repository и не включил «репозитории JPA» (я не знаю, что это значит). Обратите внимание, что все работает должным образом, пока я не попытаюсь автоматически подключить UserRepository внутри фрагмента.
Не могли бы вы объяснить, что «работает»? Вы имеете в виду, что у вас нет исключений? Или вы имеете в виду, что действительно можете использовать репозитории?
Привет, Микаэль, когда я говорю «работает», я имею в виду, что доступ к данным работает, как ожидалось. В настоящее время я использую EntityManager и вручную создаю запросы с использованием языка запросов Java Persistence Query Language внутри фрагментов. Этой части я бы хотел избежать, потому что теперь я реализую с EntityManager метод, который обычно получаю бесплатно (например, findByFirstNameAndLastName).
@NikolaosGeorgiou, ты решил это?
@NikolaosGeorgiou Круговая трассировка стека зависимостей сильно отличается от NPE. И в этом случае приложение даже не запускалось. Я сомневаюсь, что у вас нет проблемы циклической зависимости. Я подозреваю, что один из ваших bean-компонентов не инициализируется и выдает NPE, когда вы вызываете какой-либо метод для этого неинициализированного bean-компонента. Используйте режим отладчика, чтобы узнать, какая переменная имеет значение NULL. Это должен быть какой-либо из автосоединенных бобов.




От документация
Если вы используете конфигурацию Spring XML, у вас должно быть следующее:
<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa = "http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<jpa:repositories base-package = "com.acme.repositories" />
</beans>
Если вместо этого вы используете конфигурацию Java, у вас должно быть следующее:
@Configuration
@EnableJpaRepositories("com.acme.repositories")
class ApplicationConfiguration {
@Bean
EntityManagerFactory entityManagerFactory() {
// …
}
}
Также вам необходимо добавить аннотацию @Repository в свои репозитории:
@Repository
public interface UserRepository extends JpaRepository<User, Long>, UserExtraLogic {
User findByFirstNameAndLastName(String firstName, String lastName);
}
Объяснение
От документация
Using the
repositorieselement looks up Spring Data repositories as described in “Creating Repository Instances”. Beyond that, it activates persistence exception translation for all beans annotated with@Repository, to let exceptions being thrown by the JPA persistence providers be converted into Spring’sDataAccessExceptionhierarchy.
Привет, Микаэль, спасибо за помощь. Я понимаю, что забыл упомянуть, что мое приложение находится в Spring Boot 2.1.0. Мне жаль, что я забыл об этом упомянуть. Я думаю, что то, о чем вы говорите, уже предоставлено мне Spring Boot.
Это неверно. Я также вижу, что NPE запускаются из кода фрагмента репозитория при попытке доступа к производным методам запроса в базовом репозитории.
Вы можете лениво загрузить свой репозиторий с помощью ObjectFactory<T> (концепция Spring) или Provider<T> (стандартный java api).
class UserExrtaLogicImpl implements UserExtraLogic {
@Autowired
private ObjectFactory<UserRepository> userRepository;
public void soSomething() {
userRepository().getObject().findById(xxx);
}
}
@ MạnhQuyếtNguyễn Я пробовал аналогичный подход, который не сработал из-за слишком раннего вызова getObject(). Это действительно работает. При этом он не такой идиоматичный, как @Lazy, и определенно не идентичен, поэтому отрицательный голос не оправдан.
getObject() being called too early. -> Итак, вы можете показать, как вы вызываете это на раннем этапе кода. Если вы получите доступ к нему, как в моем примере, это не проблема.
У меня точно такие же шаблоны кода, и я столкнулся с той же проблемой в недавнем проекте, и я, наконец, решил ее, используя @Lazy для ленивой инициализации UserRepository:
class UserExrtaLogicImpl implements UserExtraLogic {
@Lazy
@Autowired
private UserRepository userRepository;
}
Ты прав. Проблема круговой зависимости может быть решена с помощью @Lazy, но я очень сомневаюсь, что у @Nikolaos Georgiou есть такая проблема. Описанная ими постановка проблемы не имеет проблемы циклической зависимости.
Обратите внимание на это в документации.
Extending the fragment interface with your repository interface combines the CRUD and custom functionality and makes it available to clients.
Когда вы расширяете интерфейс фрагментов, ваш последний репозиторий также будет включать его. Это его благодать. Если вы хотите получить доступ к исходной логике репозитория, я могу предложить вам 3 метода.
Не включайте циклические зависимости, поскольку это не очень хорошая практика.
Привет. Не могли бы вы предоставить трассировку стека исключения? Есть ли в вашем интерфейсе аннотация
@Repository? Включили ли вы репозитории JPA в своей конфигурации?