引言
这篇博客主要介绍了如何将Bean 和QBean放在不同的包
- 用 springBoot
自动
代理生成 QBean 必须和 Bean 在同一个
包的根路径
下,才会被 springboot 识别。 - 在代理过程中用到的几个关键类,待会扩展时需要用到它们。
- 在这里我们需特别注意 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);
}
}