不知道从啥时候开始项目上就一直用MyBatis,其实我我的更喜欢JPA些,由于JPA看起来OO的思想更强烈些,因此这才最近把JPA拿出来再看一看,使用起来也很简单,除了定义Entity实体外,声明本身的业务接口继承JpaRepository接口,什么逻辑也不用写,基本的增删改查,分页,排序就都搞定了。java
我在实现JpaRepository接口时就有个疑问,那么实现类是什么?若是用过MyBatis确定也知道,是接口和实现类之间有一个代理类专门来处理这块的业务,那么JPA这块是否也会有一个代理类来处理一样的业务呢? 整体来讲咱们有两个疑问,关键字分别是:接口实现类,代理类是什么。mysql
首先从spring-boot-autoconfiguration.jar中下的spring.factories中咱们能够看到JPA的自动配置须要从JpaRepositoriesAutoConfiguration开始着手。 我先画了一张总的Spring Data JPA自动配置流程图,能够有个大概的认识,下面会从源代码层面再来读一读其工做原理,和关键代码都分布在那里。
spring
由于咱们在pom中导入了spring-data-jpa.jar,数据库驱动jar包为系统默认jar,也就是说他们会出如今程序运行的classpath上,而且咱们在yml文件中配置了数据源,因此在springboot程序启动中,springboot自动配置中关于JPA的自动配置就已经开始工做了,具体的自动配置类会从JpaRepositoriesAutoConfiguration开始。sql
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3307/readinglist?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval\ =true spring.datasource.username=root spring.datasource.password=000 spring.jpa.generate-ddl=false spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true
从代码中能够看到JPA的默认实现是Hibernate,因此会先配置HibernateJpaAutoConfiguration,而且是在DataSource bean已经存在的状况下。数据库
@Configuration(proxyBeanMethods = false) @ConditionalOnBean(DataSource.class) @ConditionalOnClass(JpaRepository.class) @ConditionalOnMissingBean({ JpaRepositoryFactoryBean.class, JpaRepositoryConfigExtension.class }) @ConditionalOnProperty(prefix = "spring.data.jpa.repositories", name = "enabled", havingValue = "true", matchIfMissing = true) //导入JpaRepositoriesRegistrar @Import(JpaRepositoriesRegistrar.class) //先自动配置HibernateJpaAutoConfiguration, TaskExecutionAutoConfiguration @AutoConfigureAfter({ HibernateJpaAutoConfiguration.class, TaskExecutionAutoConfiguration.class }) public class JpaRepositoriesAutoConfiguration { }
@Configuration(proxyBeanMethods = false) @ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EntityManager.class, SessionImplementor.class }) @EnableConfigurationProperties(JpaProperties.class) @AutoConfigureAfter({ DataSourceAutoConfiguration.class }) @Import(HibernateJpaConfiguration.class) public class HibernateJpaAutoConfiguration { }
这里你首先会看到必须是DataSource bean存在的状况下,其次还有一个关键信息就是不存在JpaRepositoryFactoryBean bean的状况下才会执行该自动配置,也就是说若是你想根据本身的业务从新实现一个FactoryBean,那么该自动配置则不会执行。 那么看起来JpaRepositoryFactoryBean可能看起来有点眼熟哦。springboot
JpaRepositoryFactoryBean位于org.springframework.data.jpa.repository.support包下app
JpaRepositoriesRegistrar中静态内部类使用了@EnableJpaRepositories开启JPA。若是不是SpringBoot项目中该注解是须要手动开启。ide
class JpaRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport { @EnableJpaRepositories private static class EnableJpaRepositoriesConfiguration { } }
JpaRepositoriesRegistrar又继承了抽象类AbstractRepositoryConfigurationSourceSupport类。这是一个ImportBeanDefinitionRegistrar,设计目的就是在SpringBoot自动发现机制中发现用户自定义的JpaRepository。在Spring容器启动中,该ImportBeanDefinitionRegistrar就会执行。函数
public abstract class AbstractRepositoryConfigurationSourceSupport implements ImportBeanDefinitionRegistrar, BeanFactoryAware, ResourceLoaderAware, EnvironmentAware { }
在AbstractRepositoryConfigurationSourceSupport类中重写了registerBeanDefinitions方法,这个方法里又把实例化的任务交给了RepositoryConfigurationDelegate#registerRepositoriesIn()。
AbstractRepositoryConfigurationSourceSupport#registerBeanDefinitionsspring-boot
@Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) { RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate( getConfigurationSource(registry, importBeanNameGenerator), this.resourceLoader, this.environment); delegate.registerRepositoriesIn(registry, getRepositoryConfigurationExtension()); } @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { registerBeanDefinitions(importingClassMetadata, registry, null); }
RepositoryConfigurationDelegate#registerRepositoriesIn
public class RepositoryConfigurationDelegate { public List<BeanComponentDefinition> registerRepositoriesIn(BeanDefinitionRegistry registry, RepositoryConfigurationExtension extension) { extension.registerBeansForRoot(registry, this.configurationSource); RepositoryBeanDefinitionBuilder builder = new RepositoryBeanDefinitionBuilder(registry, extension, this.configurationSource, this.resourceLoader, this.environment); List<BeanComponentDefinition> definitions = new ArrayList(); StopWatch watch = new StopWatch(); watch.start(); //extension.getRepositoryConfigurations() 会扫描相应的包并找到用户自定义JpaRepository接口 Collection<RepositoryConfiguration<RepositoryConfigurationSource>> configurations = extension.getRepositoryConfigurations(this.configurationSource, this.resourceLoader, this.inMultiStoreMode); Map<String, RepositoryConfiguration<?>> configurationsByRepositoryName = new HashMap(configurations.size()); Iterator var8 = configurations.iterator(); while(var8.hasNext()) { RepositoryConfiguration<? extends RepositoryConfigurationSource> configuration = (RepositoryConfiguration)var8.next(); configurationsByRepositoryName.put(configuration.getRepositoryInterface(), configuration); //对于每一个扫描找到的用户自定义JpaRepository,构建一个BeanDefinitionBuilder, //就是在这个步骤中将该BeanDefinition同JpaRepositoryFactoryBean创建关系 BeanDefinitionBuilder definitionBuilder = builder.build(configuration); extension.postProcess(definitionBuilder, this.configurationSource); if (this.isXml) { extension.postProcess(definitionBuilder, (XmlRepositoryConfigurationSource)this.configurationSource); } else { extension.postProcess(definitionBuilder, (AnnotationRepositoryConfigurationSource)this.configurationSource); } //这里根据所发现的用户自定义JpaRepository接口的名字构造一个bean名称 AbstractBeanDefinition beanDefinition = definitionBuilder.getBeanDefinition(); beanDefinition.setResourceDescription(configuration.getResourceDescription()); String beanName = this.configurationSource.generateBeanName(beanDefinition); if (logger.isTraceEnabled()) { logger.trace(LogMessage.format("Spring Data %s - Registering repository: %s - Interface: %s - Factory: %s", extension.getModuleName(), beanName, configuration.getRepositoryInterface(), configuration.getRepositoryFactoryBeanClassName())); } //设置当前BeanDefinition的属性factoryBeanObjectType为用户自定义JpaRepository接口的全限定名 beanDefinition.setAttribute("factoryBeanObjectType", configuration.getRepositoryInterface()); // 如今把这个bean注册到容器 registry.registerBeanDefinition(beanName, beanDefinition); definitions.add(new BeanComponentDefinition(beanDefinition, beanName)); } potentiallyLazifyRepositories(configurationsByRepositoryName, registry, this.configurationSource.getBootstrapMode()); watch.stop(); return definitions; } }
RepositoryBeanDefinitionBuilder#build
public BeanDefinitionBuilder build(RepositoryConfiguration<?> configuration) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(configuration.getRepositoryFactoryBeanClassName()); builder.getRawBeanDefinition().setSource(configuration.getSource()); builder.addConstructorArgValue(configuration.getRepositoryInterface()); builder.addPropertyValue("queryLookupStrategyKey", configuration.getQueryLookupStrategyKey()); builder.addPropertyValue("lazyInit", configuration.isLazyInit()); builder.setLazyInit(configuration.isLazyInit()); builder.setPrimary(configuration.isPrimary()); configuration.getRepositoryBaseClassName().ifPresent((it) -> { builder.addPropertyValue("repositoryBaseClass", it); }); NamedQueriesBeanDefinitionBuilder definitionBuilder = new NamedQueriesBeanDefinitionBuilder(this.extension.getDefaultNamedQueryLocation()); configuration.getNamedQueriesLocation().ifPresent(definitionBuilder::setLocations); builder.addPropertyValue("namedQueries", definitionBuilder.build(configuration.getSource())); this.registerCustomImplementation(configuration).ifPresent((it) -> { builder.addPropertyReference("customImplementation", it); builder.addDependsOn(it); }); BeanDefinitionBuilder fragmentsBuilder = BeanDefinitionBuilder.rootBeanDefinition(RepositoryFragmentsFactoryBean.class); List<String> fragmentBeanNames = (List)this.registerRepositoryFragmentsImplementation(configuration).map(RepositoryFragmentConfiguration::getFragmentBeanName).collect(Collectors.toList()); fragmentsBuilder.addConstructorArgValue(fragmentBeanNames); builder.addPropertyValue("repositoryFragments", ParsingUtils.getSourceBeanDefinition(fragmentsBuilder, configuration.getSource())); return builder; }
我在builder()里调试了一下代码,程序执行到该方法倒数第二行代码时,能够BeanDefinitionBuilder#beanClass就是org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean。
从上面两段代码分析来看,无论用户建立多少个JpaRepository,最终注入Spring容器的bean都是来自JpaRepositoryFactoryBean工厂来建立。每一个开发人员自定义的JpqRepository又都是针对不一样的领域模型的,好比说UserRepository,OrderRepository,OrderLineItemRepository。
@Autowired private BookRepository bookRepository;
当你定义了的BookRepository后,在使用时又是如何从Spring容器中获取bean的。上面既然说了BeanDefinitionBuilder会和JpaRepositoryFactoryBean创建联系,那咱们仍是从JpaRepositoryFactoryBean入手。
public class JpaRepositoryFactoryBean<T extends Repository<S, ID>, S, ID> extends TransactionalRepositoryFactoryBeanSupport<T, S, ID> { //构造函数,这里repositoryInter就是你自定义的JpaRepository public JpaRepositoryFactoryBean(Class<? extends T> repositoryInterface) { super(repositoryInterface); } @Override protected RepositoryFactorySupport doCreateRepositoryFactory() { Assert.state(entityManager != null, "EntityManager must not be null!"); return createRepositoryFactory(entityManager); } //这个方法会返回JpaRepositoryFactory protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) { JpaRepositoryFactory jpaRepositoryFactory = new JpaRepositoryFactory(entityManager); jpaRepositoryFactory.setEntityPathResolver(entityPathResolver); jpaRepositoryFactory.setEscapeCharacter(escapeCharacter); if (queryMethodFactory != null) { jpaRepositoryFactory.setQueryMethodFactory(queryMethodFactory); } return jpaRepositoryFactory; } }
这段代码咱们会关注两个地方,一个是构造函数,构造函数的参数repositoryInterface就是用户自定义的接口,一个是createRepositoryFactory(),Spring要建立JpaRepository的实现类,会先建立一个JpaRepositoryFactory,而后具体接口的实现类,或者叫作代理会交给该工厂类实现。
public class JpaRepositoryFactory extends RepositoryFactorySupport { }
JpaRepositoryFactory继承了抽象类RepositoryFactorySupport,而RepositoryFactorySupport又实现了两个Spring接口BeanClassLoaderAware,BeanFactoryAware。
RepositoryFactorySupport位于spring-data-common.jar内。
public <T> T getRepository(Class<T> repositoryInterface, RepositoryFragments fragments) { //repositoryInterface为用户自定义的JpaRepository,这里为BookRepository。 RepositoryMetadata metadata = this.getRepositoryMetadata(repositoryInterface); RepositoryComposition composition = this.getRepositoryComposition(metadata, fragments); RepositoryInformation information = this.getRepositoryInformation(metadata, composition); this.validate(information, composition); //target为SimpleJpaRepository。 Object target = this.getTargetRepository(information); ProxyFactory result = new ProxyFactory(); result.setTarget(target); result.setInterfaces(new Class[]{repositoryInterface, Repository.class, TransactionalProxy.class}); if (MethodInvocationValidator.supports(repositoryInterface)) { result.addAdvice(new MethodInvocationValidator()); } result.addAdvisor(ExposeInvocationInterceptor.ADVISOR); this.postProcessors.forEach((processor) -> { processor.postProcess(result, information); }); if (DefaultMethodInvokingMethodInterceptor.hasDefaultMethods(repositoryInterface)) { result.addAdvice(new DefaultMethodInvokingMethodInterceptor()); } ProjectionFactory projectionFactory = this.getProjectionFactory(this.classLoader, this.beanFactory); Optional<QueryLookupStrategy> queryLookupStrategy = this.getQueryLookupStrategy(this.queryLookupStrategyKey, this.evaluationContextProvider); result.addAdvice(new QueryExecutorMethodInterceptor(information, projectionFactory, queryLookupStrategy, this.namedQueries, this.queryPostProcessors, this.methodInvocationListeners)); composition = composition.append(RepositoryFragment.implemented(target)); result.addAdvice(new RepositoryFactorySupport.ImplementationMethodExecutionInterceptor(information, composition, this.methodInvocationListeners)); //repository为SimpleJpaRepository T repository = result.getProxy(this.classLoader); return repository; }
这是一个关键方法,this.getTargetRepository会建立一个SimpleJpaRepository对象。该对象知道本身具体操做那个领域对象,随后又基于此类建立一个代理对象,设置Interceptor对象后返回该代理对象。 当真正的SimpleJpaRepository代理对象被建立以后,包裹该对象的JpaRepositoryFactoryBean对象就是咱们最终要使用bean的FactoryBean,Spring容器中,用户自定义的bean保存的其实是一个JpaRepositoryFactoryBean。
@Repository @Transactional(readOnly = true) public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> { //这里就是咱们经常使用的CURD方法了,终于看到了庐山真面目。 }
综上所述,注入bean实例化过程就结束了,能够进行注入了,根据上面的分析,每一个用户自定义的JpaRepository实际上在Spring容器中保存的是一个JpaRepositoryFactoryBean,这是一个FactoryBean。当对JpaRepository进行注入并调用时会FactoryBean#getObject()获取要调用SimpleJpaRepository的代理对象。
上面我本身提到的两个问题,到了这里咱们就有一个明确的答案了,首先回答代理是什么,从上面调试代码能够看出来repository的h属性是JdkDynamicAopProxy对象。当程序执行的时候会经过调用JdkDynamicAopProxy.invoke(),好比说调用JpaRepository.findAll(), 代理对象的建立逻辑都隐藏在JdkDynamicAopProxy中,而在这里这个代理对象就是SimpleJpaRepository对象,也是你的自定义JpaRepository的实现类。
SimpleJpaRepository对象位于 org.springframework.data.jpa.repository.support包下。