如何扩展QuerydslJpaPredicateExecutor并实现Spring构造参数自动注入?
你遇到的错误是因为JpaEntityInformation并非Spring容器中的Bean,它是由Spring Data JPA的仓库工厂动态创建的,无法通过常规依赖注入获取;同时你的自定义实现类SliceableRepositoryImpl未被Spring Data JPA的仓库工厂正确识别,导致无法自动传递构造所需参数。以下是两种可行的解决方案:
解决方案一:自定义全局仓库基类(适用于所有JPA仓库)
适合需要统一修改所有仓库Querydsl查询逻辑的场景,所有JPA仓库都会基于该基类创建。
- 创建自定义仓库基类,继承
SimpleJpaRepository并实现QuerydslPredicateExecutor:
import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.support.JpaEntityInformation; import org.springframework.data.jpa.repository.support.Querydsl; import org.springframework.data.jpa.repository.support.SimpleJpaRepository; import org.springframework.data.jpa.repository.support.SimpleEntityPathResolver; import com.querydsl.core.types.Predicate; import com.querydsl.jpa.impl.JpaQuery; import jakarta.persistence.EntityManager; import java.util.List; import java.util.Optional; public class SliceableRepositoryImpl<T, ID> extends SimpleJpaRepository<T, ID> implements QuerydslPredicateExecutor<T> { private final EntityManager entityManager; private final Querydsl querydsl; // 接收仓库工厂提供的构造参数 public SliceableRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) { super(entityInformation, entityManager); this.entityManager = entityManager; var path = SimpleEntityPathResolver.INSTANCE.createPath(entityInformation.getJavaType()); this.querydsl = new Querydsl(entityManager, new com.querydsl.core.types.dsl.PathBuilder<>(path.getType(), path.getMetadata())); } // 重写需要修改的Querydsl查询方法 @Override public Page<T> findAll(Predicate predicate, Pageable pageable) { // 在这里编写自定义逻辑,比如添加默认过滤条件、修改分页规则等 JpaQuery<T> query = createQuery(predicate); long total = count(predicate); List<T> content = querydsl.applyPagination(pageable, query).fetch(); return new org.springframework.data.domain.PageImpl<>(content, pageable, total); } // 实现QuerydslPredicateExecutor的其他方法,复用默认逻辑 @Override public Optional<T> findOne(Predicate predicate) { return QuerydslJpaPredicateExecutor.super.findOne(predicate); } @Override public Iterable<T> findAll(Predicate predicate) { return QuerydslJpaPredicateExecutor.super.findAll(predicate); } @Override public Iterable<T> findAll(Predicate predicate, com.querydsl.core.types.OrderSpecifier<?>... orders) { return QuerydslJpaPredicateExecutor.super.findAll(predicate, orders); } @Override public Iterable<T> findAll(com.querydsl.core.types.OrderSpecifier<?>... orders) { return QuerydslJpaPredicateExecutor.super.findAll(orders); } @Override public long count(Predicate predicate) { return QuerydslJpaPredicateExecutor.super.count(predicate); } @Override public boolean exists(Predicate predicate) { return QuerydslJpaPredicateExecutor.super.exists(predicate); } // 辅助方法:创建Querydsl查询实例 private JpaQuery<T> createQuery(Predicate predicate) { var path = SimpleEntityPathResolver.INSTANCE.createPath(getDomainClass()); return new JpaQuery<>(entityManager).select(path).from(path).where(predicate); } }
- 在Spring Boot启动类(或配置类)中指定自定义基类:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @SpringBootApplication @EnableJpaRepositories(repositoryBaseClass = SliceableRepositoryImpl.class) public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } }
- 定义仓库接口,继承
JpaRepository和QuerydslPredicateExecutor:
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.querydsl.QuerydslPredicateExecutor; public interface MysRepository extends JpaRepository<MyEntity, Long>, QuerydslPredicateExecutor<MyEntity> { }
解决方案二:针对单个仓库的自定义实现(仅修改特定仓库)
如果只需要修改某一个仓库的Querydsl逻辑,可使用这种方式。
- 定义自定义方法接口(存放需要重写的方法):
import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import com.querydsl.core.types.Predicate; public interface MysRepositoryCustom { Page<MyEntity> findAll(Predicate predicate, Pageable pageable); }
- 创建自定义实现类,继承
QuerydslJpaPredicateExecutor并实现自定义接口:
import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.support.JpaEntityInformation; import org.springframework.data.jpa.repository.support.QuerydslJpaPredicateExecutor; import org.springframework.data.jpa.repository.support.SimpleEntityPathResolver; import com.querydsl.core.types.Predicate; import jakarta.persistence.EntityManager; public class MysRepositoryImpl extends QuerydslJpaPredicateExecutor<MyEntity> implements MysRepositoryCustom { // 接收仓库工厂传递的构造参数 public MysRepositoryImpl(JpaEntityInformation<MyEntity, ?> entityInformation, EntityManager entityManager) { super(entityInformation, entityManager, SimpleEntityPathResolver.INSTANCE, null); } @Override public Page<MyEntity> findAll(Predicate predicate, Pageable pageable) { // 编写自定义查询逻辑,比如添加全局过滤条件 Predicate modifiedPredicate = predicate.and(QMyEntity.myEntity.isActive.eq(true)); return super.findAll(modifiedPredicate, pageable); } }
- 主仓库接口继承
JpaRepository、QuerydslPredicateExecutor和自定义接口:
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.querydsl.QuerydslPredicateExecutor; public interface MysRepository extends JpaRepository<MyEntity, Long>, QuerydslPredicateExecutor<MyEntity>, MysRepositoryCustom { }
关键说明
- Spring Data JPA会自动识别命名为
XxxRepositoryImpl的实现类(对应XxxRepository接口),将自定义方法的逻辑委托给该实现类。 JpaEntityInformation、EntityManager等参数由仓库工厂在创建仓库实例时自动传递,无需手动注入,因为它们不是Spring容器中的Bean,而是仓库工厂动态生成的对象。
内容的提问来源于stack exchange,提问作者membersound
相关产品推荐
相关产品推荐

