RepositoryFactorySupport
根據(jù)repo注解生成bean
- 根據(jù)接口注解獲取元數(shù)據(jù),獲取實現(xiàn)類累贤,通常都是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的初始化
根據(jù)每個方法構(gòu)造RepositoryQuery
RepositoryQuery
根據(jù)方法上的注解生成不同的查詢處理類少漆,也就是repo接口被調(diào)用時臼膏,執(zhí)行的查詢子方法
SimpleJpaQuery
方法頭上@Query注解的nativeQuery屬性缺省值為false,也就是使用JPQL示损,此時會創(chuàng)建SimpleJpaQuery實例渗磅,并通過兩個StringQuery類實例分別持有query jpql語句和根據(jù)query jpql計算拼接出來的countQuery jpql語句;
NativeJpaQuery
方法頭上@Query注解的nativeQuery屬性如果顯式的設(shè)置為nativeQuery=true检访,也就是使用原生SQL始鱼,此時就會創(chuàng)建NativeJpaQuery實例;
PartTreeJpaQuery
方法頭上未進行@Query注解脆贵,將使用spring-data-jpa獨創(chuàng)的方法名識別的方式進行sql語句拼接医清,此時在spring-data-jpa內(nèi)部就會創(chuàng)建一個PartTreeJpaQuery實例;
NamedQuery
使用javax.persistence.NamedQuery注解訪問數(shù)據(jù)庫的形式卖氨,此時在spring-data-jpa內(nèi)部就會根據(jù)此注解選擇創(chuàng)建一個NamedQuery實例会烙;
StoredProcedureJpaQuery
顧名思義负懦,在Repository接口的方法頭上使用org.springframework.data.jpa.repository.query.Procedure注解,也就是調(diào)用存儲過程的方式訪問數(shù)據(jù)庫柏腻,此時在spring-data-jpa內(nèi)部就會根據(jù)@Procedure注解而選擇創(chuàng)建一個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
關(guān)鍵字作隔離
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
關(guān)鍵字
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));
}
}
}
執(zhí)行方法
- QueryExecutorMethodInterceptor.doInvoke (找到初始化構(gòu)造的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 執(zhí)行拼裝好的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
- 默認實現(xiàn)了如
findOne颗品、getOne、findAll贫导、delete
等常用的方法
SimpleJpaRepository方法列表