Есть ли способ зарегистрировать базовый класс репозитория с автоматической конфигурацией загрузки spring?
У нас есть базовый класс репозитория JPA с некоторыми дополнительными утилитами, которые мы используем в наших проектах. После Spring Документация JPA данных > мы создали класс и использовали аннотацию @EnableJpaRepositories в классе конфигурации, как в следующем примере:
@Configuration
@EnableJpaRepositories(basePackageClasses = MyApplication.class,
repositoryBaseClass = MyJpaRepositoryImpl.class)
public class SpringDataJpaMyRepositoryConfiguration {
}
Мы также устанавливаем атрибут basePackageClasses, чтобы наши репозитории были найдены, так как класс конфигурации не находится в корневом пакете приложения. Все работает так, как ожидалось, поэтому проблем пока нет.
Теперь мы хотели бы создать стартер загрузки spring, чтобы добавить базовый класс репозитория к нашим проектам без дальнейшей настройки, но мы не знаем, как это сделать. Если мы создадим класс AutoConfiguration с параметром аннотации EnableJpaRepositories, атрибутом repositoryBaseClass, стратегия поиска в автоматическом репозитории, которая ищет репозитории в классе, аннотированном с помощью @SpringBootApplication, больше не работает.
И мы не можем использовать атрибут basePackageClasses, поскольку мы не знаем основной класс или пакет проекта, используя автоконфигурацию.
Есть ли способ сделать это? Может быть, переопределив некоторые bean в нашей автоконфигурации?
Идеальный способ - это то, что позволяет установить базовый класс репозитория без необходимости повторного определения всей автоконфигурации spring Data JPA.
Ответы
Ответ 1
РЕДАКТОР: Я почти переписал свой ответ - я неправильно понял исходный вопрос
Это не самое приятное решение, но единственный способ, которым я вижу это, - использовать SpEL внутри @EnableJpaRepositories
.
Затем вы можете перейти в свою автоматическую конфигурацию и использовать @ConditionalOnProperty
только для автоматической настройки, если установлено свойство базового пакета
@Configuration
@ConditionalOnProperty("repositories-base-packages")
public class BaseRepositoryAutoConfiguration {
@Configuration
@EnableJpaRepositories(
repositoryBaseClass = MyJpaRepositoryImpl.class,
basePackages = "${repositories-base-packages}"
)
public static class JpaRepositoriesConfig { }
}
Затем убедитесь, что у вас есть application.properties
или application.yml
, который определяет repositories-base-packages
внутри вашего приложения.
Не уверен, как вы объявите несколько базовых пакетов, мои знания SpEL являются примитивными, поэтому не уверены, что это будет возможно.
Ответ 2
Этот вопрос заставлял меня сходить с ума в то время, поэтому я думал, что смогу помочь вам в этом.
В принципе, идея заключается в следующем:
- Создайте класс конфигурации для вашей конфигурации Jpa
- Добавить @EntityScan и @EnableJpaRepositories, ссылающиеся на тот же класс конфигурации, что и basePackageClass
- Импортируйте этот класс конфигурации в свою конфигурацию автоконфигурации
- Создайте аннотацию, которую вы затем можете повторно использовать там, где вам нужна конфигурация Jpa
В вашем примере вы используете свой класс приложений Spring в качестве базы для сканирования.
Я поставил образец проекта в POC основные идеи в https://github.com/rdlopes/custom-jpa-demo
В этом примере существует проект для сущностей/репозиториев JPA, отображающих конфигурацию JPA:
@Configuration
@EntityScan(basePackageClasses = JpaConfiguration.class)
@EnableJpaRepositories(basePackageClasses = JpaConfiguration.class,
repositoryBaseClass = BaseRepositoryImpl.class)
public class JpaConfiguration {
}
Будьте осторожны с общей реализацией ваших репозиториев, вам нужно показать специальную подпись:
@NoRepositoryBean
public class BaseRepositoryImpl<T, ID extends Serializable>
extends SimpleJpaRepository<T, ID>
implements BaseRepository<T, ID> {
public BaseRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
}
@Override
public String someCustomMethod(ID id) {
return "Class for entity of id " + id + " is: " + getDomainClass().getSimpleName();
}
}
Затем вы можете создать свою автоматическую конфигурацию как таковую:
@Configuration
@ConditionalOnClass(CustomJpaRepositories.class)
@Import(JpaConfiguration.class)
public class JpaCustomAutoConfiguration {
}
Предоставление аннотации, чтобы держать вещи в порядке и использовать ее там, где вам нужна JPA:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface CustomJpaRepositories {
}
Использование ваших классов JPA будет таким же простым, как наличие этой аннотации, когда вы вызываете свои репозитории JPA:
@SpringBootApplication
@CustomJpaRepositories
public class CustomJpaSampleApplication {
public static void main(String[] args) {
SpringApplication.run(CustomJpaSampleApplication.class, args);
}
@Bean
public CommandLineRunner dataInitializer(UserRepository userRepository) {
return args -> {
User user1 = new User();
user1.setName("user 1");
userRepository.save(user1);
User user2 = new User();
user2.setName("user 2");
userRepository.save(user2);
userRepository.findAll()
.forEach(user -> System.out.println(
userRepository.someCustomMethod(user.getId())));
};
}
}
Надеюсь, это поможет вам пройти мимо царапин на голове: -)