SpringBoot具體整合rabbitMQ可參考:SpringBoot2.0應用(四):SpringBoot2.0之spring-data-jpa
JpaRepositories自動注入
當專案中存在org.springframework.data.jpa.repository.JpaRepository
類,並且已經注入過資料來源javax.sql.DataSource
,同時沒有注入過org.springframework.data.jpa.repository.config.JpaRepositoryConfigExtension
和org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean
時,會通過@Import
註解匯入org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfigureRegistrar
,由它完成對JPA的支援。JpaRepositoriesAutoConfigureRegistrar
又繼承自AbstractRepositoryConfigurationSourceSupport
。來看下AbstractRepositoryConfigurationSourceSupport
的具體內容。
public abstract class AbstractRepositoryConfigurationSourceSupport
implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware,
EnvironmentAware {
private ResourceLoader resourceLoader;
private BeanFactory beanFactory;
private Environment environment;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
new RepositoryConfigurationDelegate(getConfigurationSource(registry),
this.resourceLoader, this.environment).registerRepositoriesIn(registry,
getRepositoryConfigurationExtension());
}
......
}
複製程式碼
可以看出,到AbstractRepositoryConfigurationSourceSupport
對Repository
的Bean進行了定義。下面來具體看看Repositoryd的建立。
Repository的建立
我們先來看下RepositoryConfigurationDelegate
的registerRepositoriesIn
方法。
public List<BeanComponentDefinition> registerRepositoriesIn(BeanDefinitionRegistry registry,
RepositoryConfigurationExtension extension) {
extension.registerBeansForRoot(registry, configurationSource);
RepositoryBeanDefinitionBuilder builder = new RepositoryBeanDefinitionBuilder(registry, extension, resourceLoader,
environment);
List<BeanComponentDefinition> definitions = new ArrayList<>();
for (RepositoryConfiguration<? extends RepositoryConfigurationSource> configuration : extension
.getRepositoryConfigurations(configurationSource, resourceLoader, inMultiStoreMode)) {
BeanDefinitionBuilder definitionBuilder = builder.build(configuration);
extension.postProcess(definitionBuilder, configurationSource);
if (isXml) {
extension.postProcess(definitionBuilder, (XmlRepositoryConfigurationSource) configurationSource);
} else {
extension.postProcess(definitionBuilder, (AnnotationRepositoryConfigurationSource) configurationSource);
}
AbstractBeanDefinition beanDefinition = definitionBuilder.getBeanDefinition();
String beanName = configurationSource.generateBeanName(beanDefinition);
......
beanDefinition.setAttribute(FACTORY_BEAN_OBJECT_TYPE, configuration.getRepositoryInterface());
registry.registerBeanDefinition(beanName, beanDefinition);
definitions.add(new BeanComponentDefinition(beanDefinition, beanName));
}
return definitions;
}
複製程式碼
到這裡其實只是建立了repository的實體Bean的BeanDefinition。前期準備做好了,實際建立repository是在RepositoryFactorySupport
的getRepository方法。
public <T> T getRepository(Class<T> repositoryInterface, RepositoryFragments fragments) {
Assert.notNull(repositoryInterface, "Repository interface must not be null!");
Assert.notNull(fragments, "RepositoryFragments must not be null!");
RepositoryMetadata metadata = getRepositoryMetadata(repositoryInterface);
RepositoryComposition composition = getRepositoryComposition(metadata, fragments);
RepositoryInformation information = getRepositoryInformation(metadata, composition);
validate(information, composition);
Object target = getTargetRepository(information);
// Create proxy
ProxyFactory result = new ProxyFactory();
result.setTarget(target);
result.setInterfaces(repositoryInterface, Repository.class, TransactionalProxy.class);
if (MethodInvocationValidator.supports(repositoryInterface)) {
result.addAdvice(new MethodInvocationValidator());
}
result.addAdvice(SurroundingTransactionDetectorMethodInterceptor.INSTANCE);
result.addAdvisor(ExposeInvocationInterceptor.ADVISOR);
postProcessors.forEach(processor -> processor.postProcess(result, information));
result.addAdvice(new DefaultMethodInvokingMethodInterceptor());
ProjectionFactory projectionFactory = getProjectionFactory(classLoader, beanFactory);
result.addAdvice(new QueryExecutorMethodInterceptor(information, projectionFactory));
composition = composition.append(RepositoryFragment.implemented(target));
result.addAdvice(new ImplementationMethodExecutionInterceptor(composition));
return (T) result.getProxy(classLoader);
}
複製程式碼
首先去獲取我們寫的repository介面的後設資料,包括實體的ID型別,管理的實體型別等。接著獲取repository的組合,主要包含repository的方法資訊。然後再根據它倆的組合得到一個target。這個target其實就是一個SimpleJpaRepository實體,裡面包含了一些通用的方法。只有這些還不夠,於是有了後面的代理工廠,對這個target進行進一步處理。包括事務支援,異常處理和SQL創造等。我們主要看一下SQL建立。建立的方法在DeclaredQueryLookupStrategy
的resolveQuery
中。
protected RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em, NamedQueries namedQueries) {
RepositoryQuery query = JpaQueryFactory.INSTANCE.fromQueryAnnotation(method, em, evaluationContextProvider);
if (null != query) {
return query;
}
query = JpaQueryFactory.INSTANCE.fromProcedureAnnotation(method, em);
if (null != query) {
return query;
}
String name = method.getNamedQueryName();
if (namedQueries.hasQuery(name)) {
return JpaQueryFactory.INSTANCE.fromMethodWithQueryString(method, em, namedQueries.getQuery(name),
evaluationContextProvider);
}
query = NamedQuery.lookupFrom(method, em);
if (null != query) {
return query;
}
throw new IllegalStateException(
String.format("Did neither find a NamedQuery nor an annotated query for method %s!", method));
}
複製程式碼
該方法的邏輯是先找有註解的,這個包括@Query
和@Procedure
,接著是根據關鍵字建立,然後是通用方法。
本篇到此結束,如果讀完覺得有收穫的話,歡迎點贊、關注、加公眾號【貳級天災】,查閱更多精彩歷史!!!