springJPA扩展配置之querydsl

引言

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

  • 用 springBoot 自动代理生成 QBean 必须和 Bean 在同一个包的根路径下,才会被 springboot 识别。
  • 在代理过程中用到的几个关键类,待会扩展时需要用到它们。
    springJPA扩展配置之querydsl_第1张图片
  • 在这里我们需特别注意 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);
    }
}

你可能感兴趣的:(springJPA扩展配置之querydsl)