С Spring Boot 2.1.1 вам может помочь следующее решение. Ключ должен расширить JpaRepositoryFactory
и переопределить метод getRepositoryFragments(RepositoryMetadata metadata)
. В этом методе вы можете предоставить базовые (или более конкретные фрагменты) реализации для любого настраиваемого хранилища, которое следует использовать для каждого расширяющегося хранилища.
Позвольте мне показать вам пример:
QueryableReadRepository:
@NoRepositoryBean
public interface QueryableReadRepository<T> extends Repository<T, String> {
List<T> findAll(Predicate predicate);
List<T> findAll(Sort sort);
List<T> findAll(Predicate predicate, Sort sort);
List<T> findAll(OrderSpecifier<?>... orders);
List<T> findAll(Predicate predicate, OrderSpecifier<?>... orders);
Page<T> findAll(Pageable page);
Page<T> findAll(Predicate predicate, Pageable page);
Optional<T> findOne(Predicate predicate);
boolean exists(Predicate predicate);
}
Следующий интерфейс объединяет различные репозитории.
DataRepository:
@NoRepositoryBean
public interface DataRepository<T>
extends CrudRepository<T, String>, QueryableReadRepository<T> {
}
Теперь ваши репозитории конкретного домена могут расширяться из DataRepository:
@Repository
public interface UserRepository extends DataRepository<UserEntity> {
}
QueryableReadRepositoryImpl:
@Transactional
public class QueryableReadRepositoryImpl<T> extends QuerydslJpaPredicateExecutor<T>
implements QueryableReadRepository<T> {
private static final EntityPathResolver resolver = SimpleEntityPathResolver.INSTANCE;
private final EntityPath<T> path;
private final PathBuilder<T> builder;
private final Querydsl querydsl;
public QueryableReadRepositoryImpl(JpaEntityInformation<T, ?> entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager, resolver, null);
this.path = resolver.createPath(entityInformation.getJavaType());
this.builder = new PathBuilder<T>(path.getType(), path.getMetadata());
this.querydsl = new Querydsl(entityManager, builder);
}
@Override
public Optional<T> findOne(Predicate predicate) {
return super.findOne(predicate);
}
@Override
public List<T> findAll(OrderSpecifier<?>... orders) {
return super.findAll(orders);
}
@Override
public List<T> findAll(Predicate predicate, Sort sort) {
return executeSorted(createQuery(predicate).select(path), sort);
}
@Override
public Page<T> findAll(Predicate predicate, Pageable pageable) {
return super.findAll(predicate, pageable);
}
@Override
public List<T> findAll(Predicate predicate) {
return super.findAll(predicate);
}
public List<T> findAll(Sort sort) {
return executeSorted(createQuery().select(path), sort);
}
@Override
public Page<T> findAll(Pageable pageable) {
final JPQLQuery<?> countQuery = createCountQuery();
JPQLQuery<T> query = querydsl.applyPagination(pageable, createQuery().select(path));
return PageableExecutionUtils.getPage(
query.distinct().fetch(),
pageable,
countQuery::fetchCount);
}
private List<T> executeSorted(JPQLQuery<T> query, Sort sort) {
return querydsl.applySorting(sort, query).distinct().fetch();
}
}
CustomRepositoryFactoryBean
public class CustomRepositoryFactoryBean<T extends Repository<S, I>, S, I>
extends JpaRepositoryFactoryBean<T, S, I> {
public CustomRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
super(repositoryInterface);
}
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new CustomRepositoryFactory(entityManager);
}
CustomRepositoryFactory
public class CustomRepositoryFactory extends JpaRepositoryFactory {
private final EntityManager entityManager;
public CustomRepositoryFactory(EntityManager entityManager) {
super(entityManager);
this.entityManager = entityManager;
}
@Override
protected RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata) {
RepositoryFragments fragments = super.getRepositoryFragments(metadata);
if (QueryableReadRepository.class.isAssignableFrom(
metadata.getRepositoryInterface())) {
JpaEntityInformation<?, Serializable> entityInformation =
getEntityInformation(metadata.getDomainType());
Object queryableFragment = getTargetRepositoryViaReflection(
QueryableReadRepositoryImpl.class, entityInformation, entityManager);
fragments = fragments.append(RepositoryFragment.implemented(queryableFragment));
}
return fragments;
}
Основной класс:
@EnableJpaRepositories(repositoryFactoryBeanClass = CustomRepositoryFactoryBean.class)
public class App {
}
Преимущество этого заключается в том, что вы предоставляете только одну (фрагментную) реализацию для пользовательского репо. Базовая реализация репозитория по-прежнему является реализацией Spring по умолчанию. В примере предоставлено новое хранилище, но вы также можете просто переопределить реализацию по умолчанию QuerydslPredicateExecutor
в CustomRepositoryFactory