RepositoryFactorySupport
根据repo注解生成bean
RepositoryFactorySupport.getRepository
- 根据接口注解获取元数据,获取实现类,通常都是SimpleJpaRepository
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
if (isQueryDslExecutor(metadata.getRepositoryInterface())) {
return QueryDslJpaRepository.class;
} else {
return SimpleJpaRepository.class;
}
}
- 使用ProxyFactory生成接口代理类
请检索org.springframework.aop.framework.ProxyFactory的使用,非常有用
- QueryExecutorMethodInterceptor的初始化
根据每个方法构造RepositoryQuery
RepositoryQuery
根据方法上的注解生成不同的查询处理类,也就是repo接口被调用时,执行的查询子方法
RepositoryQuery关系图
SimpleJpaQuery
方法头上@Query注解的nativeQuery属性缺省值为false,也就是使用JPQL,此时会创建SimpleJpaQuery实例,并通过两个StringQuery类实例分别持有query jpql语句和根据query jpql计算拼接出来的countQuery jpql语句;
NativeJpaQuery
方法头上@Query注解的nativeQuery属性如果显式的设置为nativeQuery=true,也就是使用原生SQL,此时就会创建NativeJpaQuery实例;
PartTreeJpaQuery
方法头上未进行@Query注解,将使用spring-data-jpa独创的方法名识别的方式进行sql语句拼接,此时在spring-data-jpa内部就会创建一个PartTreeJpaQuery实例;
NamedQuery
使用javax.persistence.NamedQuery注解访问数据库的形式,此时在spring-data-jpa内部就会根据此注解选择创建一个NamedQuery实例;
StoredProcedureJpaQuery
顾名思义,在Repository接口的方法头上使用org.springframework.data.jpa.repository.query.Procedure注解,也就是调用存储过程的方式访问数据库,此时在spring-data-jpa内部就会根据@Procedure注解而选择创建一个StoredProcedureJpaQuery实例。
PartTreeJpaQuery 代码逻辑
1.PartTree
分析方法名
//正则表达式:^(find|read|get|query|stream|count|exists|delete|remove)((\p{Lu}.*?))??By
public PartTree(String source, Class<?> domainClass) {
Assert.notNull(source, "Source must not be null");
Assert.notNull(domainClass, "Domain class must not be null");
Matcher matcher = PREFIX_TEMPLATE.matcher(source);
if (!matcher.find()) {
this.subject = new Subject(null);
this.predicate = new Predicate(source, domainClass);
} else {
this.subject = new Subject(matcher.group(0));
this.predicate = new Predicate(source.substring(matcher.group().length()), domainClass);
}
}
2.PartTree.Predicate
剔除前面的动作find|read|get|query|stream|count|exists|delete|remove
后,先以Or
关键字作隔离
private void buildTree(String source, Class<?> domainClass) {
String[] split = split(source, "Or");
for (String part : split) {
nodes.add(new OrPart(part, domainClass, alwaysIgnoreCase));
}
}
3.PartTree.OrPart
再拆解And
关键字
OrPart(String source, Class<?> domainClass, boolean alwaysIgnoreCase) {
String[] split = split(source, "And");
for (String part : split) {
if (StringUtils.hasText(part)) {
children.add(new Part(part, domainClass, alwaysIgnoreCase));
}
}
}
执行方法
- QueryExecutorMethodInterceptor.doInvoke (找到初始化构造的RepositoryQuery,并execute)
private Object doInvoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
Object[] arguments = invocation.getArguments();
if (isCustomMethodInvocation(invocation)) {
Method actualMethod = repositoryInformation.getTargetClassMethod(method);
return executeMethodOn(customImplementation, actualMethod, arguments);
}
if (hasQueryFor(method)) {
return queries.get(method).execute(arguments);
}
// Lookup actual method as it might be redeclared in the interface
// and we have to use the repository instance nevertheless
Method actualMethod = repositoryInformation.getTargetClassMethod(method);
return executeMethodOn(target, actualMethod, arguments);
}
2.JpaQueryExecution 执行拼装好的SQL语句
public Object execute(AbstractJpaQuery query, Object[] values) {
Assert.notNull(query, "AbstractJpaQuery must not be null!");
Assert.notNull(values, "Values must not be null!");
Object result;
try {
result = doExecute(query, values);
} catch (NoResultException e) {
return null;
}
if (result == null) {
return null;
}
JpaQueryMethod queryMethod = query.getQueryMethod();
Class<?> requiredType = queryMethod.getReturnType();
if (void.class.equals(requiredType) || requiredType.isAssignableFrom(result.getClass())) {
return result;
}
return CONVERSION_SERVICE.canConvert(result.getClass(), requiredType)
? CONVERSION_SERVICE.convert(result, requiredType) : result;
}
SimpleJpaRepository
- 默认实现了如
findOne、getOne、findAll、delete
等常用的方法
SimpleJpaRepository方法列表
网友评论