欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

springJPA扩展配置之querydsl

程序员文章站 2022-03-27 08:52:21
引言这篇博客主要介绍了如何将Bean 和QBean放在不同的包 用 springBoot 自动代理生成 QBean 必须和 Bean 在同一个包的根路径下,才会被 springboot 识别。 在代理过程中用到的几个关键类,待会扩展时需要用到它们。 在这里我们需特别注意 SimpleEntityPathResolver 这个类,里面确立了 QBean 的在项目的位置: “%s.Q%s%s”------>"%s"表示: {Bean的包路径}+{""}+{Bean}。......
引言

这篇博客主要介绍了如何将BeanQBean放在不同的包

  • 用 springBoot 自动代理生成 QBean 必须和 Bean 在同一个包的根路径下,才会被 springboot 识别。
  • 在代理过程中用到的几个关键类,待会扩展时需要用到它们。
    springJPA扩展配置之querydsl
  • 在这里我们需特别注意 SimpleEntityPathResolver 这个类,里面确立了 QBean 的在项目的位置: “%s.Q%s%s”------>"%s"表示: {Bean的包路径}+{""}+{Bean}。
public enum SimpleEntityPathResolver implements EntityPathResolver {
	private String getQueryClassName(Class<?> domainClass) {
	        String simpleClassName = ClassUtils.getShortName(domainClass);
	        return String.format("%s.Q%s%s", domainClass.getPackage().getName(), this.getClassBase(simpleClassName), domainClass.getSimpleName());
	    }
}
自定义扩展配置

1. 创建一个 BaseJPA 接口,该接口可以定义一些公共的 query 查询方法,具体的业务dao可以继承 BaseJPA 接口 --------------------------->@NoRepositoryBean注解使该接口不实例化。

//不进行实例化
@NoRepositoryBean
public interface BaseJPA<T,ID extends Serializable> extends JpaRepository<T,ID>, JpaSpecificationExecutor<T>, QueryDslPredicateExecutor<T> {
}

2.创建一个 SimpleEntityPathResolver 枚举类,可以 copy 源码,对细节(Q 类包路径设置)进行修改。

// 主要对getQueryClassName方法进行修改
public enum SimpleEntityPathResolver implements EntityPathResolver {
    /**
     * 实例对象
     */
    INSTANCE;

    private static final String NO_CLASS_FOUND_TEMPLATE = "Did not find a query class %s for domain class %s!";
    private static final String NO_FIELD_FOUND_TEMPLATE = "Did not find a static field of the same type in %s!";
    
    @Override
    public <T> EntityPath<T> createPath(Class<T> domainClass) {
        String pathClassName = this.getQueryClassName(domainClass);

        try {
            Class<?> pathClass = ClassUtils.forName(pathClassName, domainClass.getClassLoader());
            Field field = this.getStaticFieldOfType(pathClass);
            if (field == null) {
                throw new IllegalStateException(String.format("Did not find a static field of the same type in %s!", pathClass));
            } else {
                return (EntityPath) ReflectionUtils.getField(field, (Object)null);
            }
        } catch (ClassNotFoundException var5) {
            throw new IllegalArgumentException(String.format("Did not find a query class %s for domain class %s!", pathClassName, domainClass.getName()), var5);
        }
    }

    private Field getStaticFieldOfType(Class<?> type) {
        Field[] var2 = type.getDeclaredFields();
        int var3 = var2.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            Field field = var2[var4];
            boolean isStatic = Modifier.isStatic(field.getModifiers());
            boolean hasSameType = type.equals(field.getType());
            if (isStatic && hasSameType) {
                return field;
            }
        }

        Class<?> superclass = type.getSuperclass();
        return Object.class.equals(superclass) ? null : this.getStaticFieldOfType(superclass);
    }

    private String getQueryClassName(Class<?> domainClass) {
        String simpleClassName = ClassUtils.getShortName(domainClass);
        // 在这里进行修改QBean的包路径,如在 Bean 所在包加一个子包 querydsl
        return String.format("%s.querydsl.Q%s%s", domainClass.getPackage().getName(), this.getClassBase(simpleClassName), domainClass.getSimpleName());
    }

    private String getClassBase(String shortName) {
        String[] parts = shortName.split("\\.");
        return parts.length < 2 ? "" : parts[0] + "_";
    }
}

3 .创建一个 BaseRespository 类,该类继承QueryDslJpaRepository类,实现 BaseJPA接口------->并调用了上面创建的SimpleEntityPathResolver

public class BaseRespository<T,ID extends Serializable> extends QueryDslJpaRepository<T,ID> implements BaseJPA<T,ID>{

    private final JPAQueryFactory jpaQueryFactory;
    private final EntityManager entityManager;
    private final JpaEntityInformation<T, ?> entityInformation;
    private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;

    private final EntityPath<T> path;
    private final PathBuilder<T> builder;
    private final Querydsl querydsl;
    // 先执行
    public BaseRespository(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
        this(entityInformation, entityManager, DEFAULT_ENTITY_PATH_RESOLVER);
    }
    // 后执行
    public BaseRespository(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager, EntityPathResolver resolver) {
       //调用自己创建SimpleEntityPathResolver类
       //在这里如果调用super(entityInformation, entityManager,resolver);则会去调用自带的SimpleEntityPathResolver类
        super(entityInformation, entityManager,com.yuqiyu.querydsl.sample.base.SimpleEntityPathResolver.INSTANCE);
        this.entityInformation = entityInformation;
        this.entityManager = entityManager;
        this.jpaQueryFactory = new JPAQueryFactory(HQLTemplates.DEFAULT, entityManager);
        this.path = com.yuqiyu.querydsl.sample.base.SimpleEntityPathResolver.INSTANCE.createPath(entityInformation.getJavaType());
        this.builder = new PathBuilder<>(path.getType(), path.getMetadata());
        this.querydsl = new Querydsl(entityManager, builder);
    }
    // TODO 如果BaseJPA定义了方法,在下面实现
}
  • QueryDslJpaRepository中的:父类SimpleJpaRepository----->实现了BaseJPA的JpaRepository和JpaSpecificationExecutor接口;且自身------> 实现了QueryDslPredicateExecutor 接口。

源码截取:

public class QueryDslJpaRepository<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements QueryDslPredicateExecutor<T> {
    // 会被下面的静态代码块初始化
    private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER;
    private final EntityPath<T> path;
    private final PathBuilder<T> builder;
    private final Querydsl querydsl;
    // 这个构造方法会被先调用,然后通过重载调用下面这个构造方法
    public QueryDslJpaRepository(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
        this(entityInformation, entityManager, DEFAULT_ENTITY_PATH_RESOLVER);
    }
    //被上面这个构造方法调用
    public QueryDslJpaRepository(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager, EntityPathResolver resolver) {
        super(entityInformation, entityManager);
        this.path = resolver.createPath(entityInformation.getJavaType());
        this.builder = new PathBuilder(this.path.getType(), this.path.getMetadata());
        this.querydsl = new Querydsl(entityManager, this.builder);
    }
    // 就是通过SimpleEntityPathResolver设置Q类所在的包路径
    static {
        DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;
    }
}

4. 创建一个BaseJpaRepositoryFactory 来继承 JpaRepositoryFactory类。

public class BaseJpaRepositoryFactory extends JpaRepositoryFactory {
    public BaseJpaRepositoryFactory(EntityManager entityManager) {
        super(entityManager);
    }
    @Override
    protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
        return BaseRespository.class;
    }
}

5. 创建一个BaseJpaRepositoryFactoryBean 来继承 JpaRepositoryFactoryBean类,并调用BaseJpaRepositoryFactory 。


public class BaseJpaRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends JpaRepositoryFactoryBean<T, S, ID> {
    /**
     * Creates a new {@link JpaRepositoryFactoryBean} for the given repository interface.
     *
     * @param repositoryInterface must not be {@literal null}.
     */
    public BaseJpaRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
        super(repositoryInterface);
    }
    @Override
    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
        //调用BaseJpaRepositoryFactory
        return new BaseJpaRepositoryFactory(entityManager);
    }
}

6. 通过注解启用自定义配置--------> @EnableJpaRepositories, 该注解也可以写在其他配置类里

@SpringBootApplication
@EnableJpaRepositories( repositoryFactoryBeanClass = BaseJpaRepositoryFactoryBean.class)
public class SampleStartApplication  {
    public static void main(String[] args) {
        SpringApplication.run(SampleStartApplication.class,args);
    }
}

本文地址:https://blog.csdn.net/qq_41366052/article/details/111933716