SpringDataJPA+Hibernate框架源码剖析系列文章:
- SpringDataJPA+Hibernate框架源码剖析(一)框架介绍
- SpringDataJPA+Hibernate框架源码剖析(二)框架整合 之 EntityManagerFactory的构建
- SpringDataJPA+Hibernate框架源码剖析(三)框架整合 之 Repository接口实现的生成
- SpringDataJPA+Hibernate框架源码剖析(四)框架整合 之 事务管理器的构建(包括spring的事务机制)
- SpringDataJPA+Hibernate框架源码剖析(五)框架整合 之 SpringBoot整合JPA剖析
- SpringDataJPA+Hibernate框架源码剖析(六)@PersistenceContext和@Autowired注入EntityManager的区别
SpringDataJPA+Hibernate框架整合主要关注三个方面:EntityManagerFactory的构建、Repository接口实现的生成、事务管理器的构建。
注:spring是采用注解式配置;为了控制篇幅本系列主要分析JPA和hibernate相关源码,需要配置过程和pom依赖的同学请自行百度。
EntityManagerFactory的构建
EntityManager是JPA中用于增删改查的接口,它的作用相当于一座桥梁,连接内存中的java对象和数据库的数据存储。EntityManager由容器调用EntityManagerFactory的方法获取,所以首先要构建EntityManagerFactory。
上图为构建EntityManagerFactory并且将构建成功的EntityManagerFactory交于spring容器管理的过程。主要关注两点:
-
LocalContainerEntityManagerFactoryBean是利用EntityManagerFactoryBuilder构造出来的。
-
方法的返回值为LocalContainerEntityManagerFactoryBean利用了spring的FactoryBean机制,LocalContainerEntityManagerFactoryBean在初始化时做了什么。
先看EntityManagerFactoryBuilder干了什么,首先构造EntityManagerFactoryBuilder构造函数如下图
一个四个入参前两个必填后两个可为空,后面步骤用到是再详细介绍
- jpaVendorAdapter:JPA适配器,具体ORM框架需要具体实现类,包含方言和具体ORM框架的一些配置如:showSql、databasePlatform
- jpaProperties: jap的配置信息如:hibernate.show_sql、hibernate.dialect
- persistenceUnitManager:persistence.xml文件解析器,可以解析管理多个持久化单元
- persistenceUnitRootLocation:persistence.xml的地址
然后为EntityManagerFactoryBuilder设置数据池和实体类包路径等属性后调用build,build方法也很简单创建一个LocalContainerEntityManagerFactoryBean然后将刚刚设置的各个属性赋值给LocalContainerEntityManagerFactoryBean,如下所示
public LocalContainerEntityManagerFactoryBean build() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
if (EntityManagerFactoryBuilder.this.persistenceUnitManager != null) {
entityManagerFactoryBean
.setPersistenceUnitManager(EntityManagerFactoryBuilder.this.persistenceUnitManager);
}
if (this.persistenceUnit != null) {
entityManagerFactoryBean.setPersistenceUnitName(this.persistenceUnit);
}
entityManagerFactoryBean.setJpaVendorAdapter(EntityManagerFactoryBuilder.this.jpaVendorAdapter);
if (this.jta) {
entityManagerFactoryBean.setJtaDataSource(this.dataSource);
}
else {
entityManagerFactoryBean.setDataSource(this.dataSource);
}
entityManagerFactoryBean.setPackagesToScan(this.packagesToScan);
entityManagerFactoryBean.getJpaPropertyMap().putAll(EntityManagerFactoryBuilder.this.jpaProperties);
entityManagerFactoryBean.getJpaPropertyMap().putAll(this.properties);
if (!ObjectUtils.isEmpty(this.mappingResources)) {
entityManagerFactoryBean.setMappingResources(this.mappingResources);
}
URL rootLocation = EntityManagerFactoryBuilder.this.persistenceUnitRootLocation;
if (rootLocation != null) {
entityManagerFactoryBean.setPersistenceUnitRootLocation(rootLocation.toString());
}
if (EntityManagerFactoryBuilder.this.bootstrapExecutor != null) {
entityManagerFactoryBean.setBootstrapExecutor(EntityManagerFactoryBuilder.this.bootstrapExecutor);
}
if (EntityManagerFactoryBuilder.this.persistenceUnitPostProcessors != null) {
entityManagerFactoryBean.setPersistenceUnitPostProcessors(
EntityManagerFactoryBuilder.this.persistenceUnitPostProcessors);
}
return entityManagerFactoryBean;
}
然后看LocalContainerEntityManagerFactoryBean在初始化时做了什么(FactoryBean机制不做赘述自行百度),LocalContainerEntityManagerFactoryBean的部分继承关系图如下,所以我们主要关注**afterPropertiesSet()和getObject()**方法(afterPropertiesSet()和getObject()在spring初始化工厂bean时调用,具体细节自行百度)
getObject()很简单如下
LocalContainerEntityManagerFactoryBean.afterPropertiesSet()如下
@Override
public void afterPropertiesSet() throws PersistenceException {
PersistenceUnitManager managerToUse = this.persistenceUnitManager;
if (this.persistenceUnitManager == null) {
// 一.如果未设置PersistenceUnitManager则采用默认的PersistenceUnitManager并且调用其初始化方法
this.internalPersistenceUnitManager.afterPropertiesSet();
managerToUse = this.internalPersistenceUnitManager;
}
// 二.获取persistenceUnitInfo
this.persistenceUnitInfo = determinePersistenceUnitInfo(managerToUse);
// 三.获取JpaVendorAdapter=this.jpaVendorAdapter
JpaVendorAdapter jpaVendorAdapter = getJpaVendorAdapter();
if (jpaVendorAdapter != null && this.persistenceUnitInfo instanceof SmartPersistenceUnitInfo) {
String rootPackage = jpaVendorAdapter.getPersistenceProviderRootPackage();
if (rootPackage != null) {
// 四.为persistenceUnitInfo设置持久性提供程序包名(rootPackage=org.hibernate)
((SmartPersistenceUnitInfo) this.persistenceUnitInfo).setPersistenceProviderPackageName(rootPackage);
}
}
//调用AbstractEntityManagerFactoryBean.afterPropertiesSet()
super.afterPropertiesSet();
}
有关persistenceUnitManager和persistenceUnitInfo这里重点讲一下,看了PersistenceUnitManager源码可以知道这个类的作用就是解析classpath*:META-INF/persistence.xml路径下的persistence.xml并且生成持久化单元persistenceUnitInfo,要知道一个persistence.xml可以配置多个持久化单元,而一个服务也可以有多个persistence.xml所以PersistenceUnitManager在设计上是支持持有多个persistenceUnitInfo单元的在其内部也有一个Map<String, PersistenceUnitInfo> persistenceUnitInfos用来保存多个持久化单元信息。但由于persistence.xml对实体类包名的配置比较蹩脚随着和spring框架整合方式的不断变更persistence.xml的使用渐渐越来越少,在现有的整合方式中由于不再使用persistence.xml所以在构建EntityManagerFactoryBuilder时第3第4个参数也不用传入了,在LocalContainerEntityManagerFactoryBean初始化时始终使用默认internalPersistenceUnitManager来返回一个默认的persistenceUnitInfo实体管理单元(虽然internalPersistenceUnitManager可以管理多个persistenceUnitInfo,但是LocalContainerEntityManagerFactoryBean只需要一个),也就是上图步骤一,二下文展开分析干了什么。也就是在springDataJpa的设计上是一个EntityManagerFactory只能持有一个实体管理单元persistenceUnitInfo,即如果需要多数据源配置时需要多个EntityManagerFactory才行。这也是网上搜索“springDataJpa整合多数据源配置”都是向spring注册多个EntityManagerFactory和EntityManager的原因。(这里再提一下管用EntityManagerFactoryBuilder的第三个参数persistenceUnitManager在通常情况下是可以不传的,在特殊需求下也可自定义,下文在解析一,二步骤时会提到)
步骤一internalPersistenceUnitManager.afterPropertiesSet();
步骤二主要完成的工作根据此管理器的配置准备PersistenceUnitInfo关键方法为DefaultPersistenceUnitManager.readPersistenceUnitInfos()
private List<SpringPersistenceUnitInfo> readPersistenceUnitInfos() {
List<SpringPersistenceUnitInfo> infos = new ArrayList<>(1);
String defaultName = this.defaultPersistenceUnitName;
// 因为在EntityManagerFactoryBuilder的时候设置了packagesToScan所以此处buildDefaultUnit=true;
boolean buildDefaultUnit = (this.packagesToScan != null || this.mappingResources != null);
boolean foundDefaultUnit = false;
PersistenceUnitReader reader = new PersistenceUnitReader(this.resourcePatternResolver, this.dataSourceLookup);
// persistenceXmlLocations=classpath*:META-INF/persistence.xml
// 解析persistenceXmlLocations路径下的全部文件封装成SpringPersistenceUnitInfo对象,在比较流行的springdatajpa整合方式中不再使用persistence.xml进行持久化单元配置所以此处结果为空数组。
SpringPersistenceUnitInfo[] readInfos = reader.readPersistenceUnitInfos(this.persistenceXmlLocations);
for (SpringPersistenceUnitInfo readInfo : readInfos) {
infos.add(readInfo);
if (defaultName != null && defaultName.equals(readInfo.getPersistenceUnitName())) {
foundDefaultUnit = true;
}
}
if (buildDefaultUnit) {
if (foundDefaultUnit) {
if (logger.isWarnEnabled()) {
logger.warn("Found explicit default persistence unit with name '" + defaultName + "' in persistence.xml - " +
"overriding local default persistence unit settings ('packagesToScan'/'mappingResources')");
}
}
else {
// 构建默认的PersistenceUnitInfo,在persistence.xml中比较关键的三个配置及在buildDefaultPersistenceUnitInfo时如何替代
// 1.<provider>持久化提供者org.hibernate.jpa.HibernatePersistenceProvider 代替==》在JpaVendorAdapter中指定
// 2.<properties>数据库信息和一些jpa的配置 代替==》使用JpaVendorAdapter中的配置和spring中的DataSource
// 3.实体类声明 代替==》扫描packagesToScan包下的实体类
// buildDefaultPersistenceUnitInfo主要完成的事情是构建一个默认的PersistenceUnitInfo包括3的关键信息,2信息在internalPersistenceUnitManager.afterPropertiesSet()方法调用完readPersistenceUnitInfos()方法【当前方法】后的后续逻辑中赋值,1信息在后续AbstractEntityManagerFactoryBean.afterPropertiesSet()中赋值,默认名称为default
infos.add(buildDefaultPersistenceUnitInfo());
}
}
return infos;
}
private SpringPersistenceUnitInfo buildDefaultPersistenceUnitInfo() {
SpringPersistenceUnitInfo scannedUnit = new SpringPersistenceUnitInfo();
if (this.defaultPersistenceUnitName != null) {
// 赋值默认名称defual
scannedUnit.setPersistenceUnitName(this.defaultPersistenceUnitName);
}
scannedUnit.setExcludeUnlistedClasses(true);
if (this.packagesToScan != null) {
for (String pkg : this.packagesToScan) {
// 扫描classpath下的packagesToScan路径下的全部类,里面会根据下图中的注解进行过滤,带有注解的类都会被放入SpringPersistenceUnitInfo中。注意jpa的@Entity注解注明的类是交由EntityManagerFactory管理并不是给spring容器管理。
scanPackage(scannedUnit, pkg);
}
}
// 在不使用persistence.xml时为空
if (this.mappingResources != null) {
for (String mappingFileName : this.mappingResources) {
scannedUnit.addMappingFileName(mappingFileName);
}
}
else {
Resource ormXml = getOrmXmlForDefaultPersistenceUnit();
// 在不使用persistence.xml时为空
if (ormXml != null) {
scannedUnit.addMappingFileName(DEFAULT_ORM_XML_RESOURCE);
if (scannedUnit.getPersistenceUnitRootUrl() == null) {
try {
scannedUnit.setPersistenceUnitRootUrl(
PersistenceUnitReader.determinePersistenceUnitRootUrl(ormXml));
}
catch (IOException ex) {
logger.debug("Failed to determine persistence unit root URL from orm.xml location", ex);
}
}
}
}
return scannedUnit;
}
至此LocalContainerEntityManagerFactoryBean.afterPropertiesSet()的一步骤完毕。
步骤二则是在初始化完成后的PersistenceUnitManager中获取一个PersistenceUnitInfo,获取就是上面生成的这个默认的SpringPersistenceUnitInfo。
至此LocalContainerEntityManagerFactoryBean.afterPropertiesSet()的关键步骤分析完毕,然后分析super.afterPropertiesSet()即AbstractEntityManagerFactoryBean.afterPropertiesSet()
@Override
public void afterPropertiesSet() throws PersistenceException {
// 获取EntityManagerFactoryBuilder构建时传进来的jpaVendorAdapter
JpaVendorAdapter jpaVendorAdapter = getJpaVendorAdapter();
if (jpaVendorAdapter != null) {
if (this.persistenceProvider == null) {
// 这个persistenceProvider是关键是持久化提供者,前面在构建PersistenceUnitInfo的解释里提到persistence.xml的三大关键其中一个就是<provider>持久化提供者就是在取得JpaVendorAdapter中的 SpringHibernateJpaPersistenceProvider。
this.persistenceProvider = jpaVendorAdapter.getPersistenceProvider();
}
// 获取LocalContainerEntityManagerFactoryBean.afterPropertiesSet()初始化时创建的默认PersistenceUnitInfo“defual”
PersistenceUnitInfo pui = getPersistenceUnitInfo();
// 获取之前往PersistenceUnitInfo和jpaVendorAdapter中塞的各种jpa实现的配置如方言、showsql等
Map<String, ?> vendorPropertyMap = (pui != null ? jpaVendorAdapter.getJpaPropertyMap(pui) :
jpaVendorAdapter.getJpaPropertyMap());
// 将这些配置合并规整
if (!CollectionUtils.isEmpty(vendorPropertyMap)) {
vendorPropertyMap.forEach((key, value) -> {
if (!this.jpaPropertyMap.containsKey(key)) {
this.jpaPropertyMap.put(key, value);
}
});
}
// 获取entityManagerFactory的实现,并判断当前类的定义类加载器是否可以加载到,防止因平行类加载器导致命名空间不可见
// 此处entityManagerFactoryInterface为SessionFactory.class
// 可以看下HibernateJpaVendorAdapter的构造函数
if (this.entityManagerFactoryInterface == null) {
this.entityManagerFactoryInterface = jpaVendorAdapter.getEntityManagerFactoryInterface();
if (!ClassUtils.isVisible(this.entityManagerFactoryInterface, this.beanClassLoader)) {
this.entityManagerFactoryInterface = EntityManagerFactory.class;
}
}
// 获取entityManager的实现,并判断当前类的定义类加载器是否可以加载到,防止因平行类加载器导致命名空间不可见
// 此处entityManagerInterface为Session.class
if (this.entityManagerInterface == null) {
this.entityManagerInterface = jpaVendorAdapter.getEntityManagerInterface();
if (!ClassUtils.isVisible(this.entityManagerInterface, this.beanClassLoader)) {
this.entityManagerInterface = EntityManager.class;
}
}
// 获取方言
if (this.jpaDialect == null) {
this.jpaDialect = jpaVendorAdapter.getJpaDialect();
}
}
// 是否异步初始化,基本用不上
AsyncTaskExecutor bootstrapExecutor = getBootstrapExecutor();
if (bootstrapExecutor != null) {
this.nativeEntityManagerFactoryFuture = bootstrapExecutor.submit(this::buildNativeEntityManagerFactory);
}
else {
// 构建对应ORM实现的EntityManagerFactory这里构建的是SessionFactoryImpl
// SessionFactoryImpl的构建过程贼鸡儿复杂,没办法全部贴出来,后面执行源码分析过程中用到那些分析那些
this.nativeEntityManagerFactory = buildNativeEntityManagerFactory();
}
// Wrap the EntityManagerFactory in a factory implementing all its interfaces.
// This allows interception of createEntityManager methods to return an
// application-managed EntityManager proxy that automatically joins
// existing transactions.
// 为nativeEntityManagerFactory包装一次代理,使用的是JDK的动态代理,目的是可以为nativeEntityManagerFactory的方法进行监听添加横切逻辑
this.entityManagerFactory = createEntityManagerFactoryProxy(this.nativeEntityManagerFactory);
}
protected EntityManagerFactory createEntityManagerFactoryProxy(@Nullable EntityManagerFactory emf) {
Set<Class<?>> ifcs = new LinkedHashSet<>();
Class<?> entityManagerFactoryInterface = this.entityManagerFactoryInterface;
if (entityManagerFactoryInterface != null) {
ifcs.add(entityManagerFactoryInterface);
}
else if (emf != null) {
ifcs.addAll(ClassUtils.getAllInterfacesForClassAsSet(emf.getClass(), this.beanClassLoader));
}
else {
ifcs.add(EntityManagerFactory.class);
}
ifcs.add(EntityManagerFactoryInfo.class);
try {
// 为EntityManagerFactory包装一层代理,InvocationHandler为ManagedEntityManagerFactoryInvocationHandler
return (EntityManagerFactory) Proxy.newProxyInstance(this.beanClassLoader,
ClassUtils.toClassArray(ifcs), new ManagedEntityManagerFactoryInvocationHandler(this));
}
catch (IllegalArgumentException ex) {
if (entityManagerFactoryInterface != null) {
throw new IllegalStateException("EntityManagerFactory interface [" + entityManagerFactoryInterface +
"] seems to conflict with Spring's EntityManagerFactoryInfo mixin - consider resetting the "+
"'entityManagerFactoryInterface' property to plain [javax.persistence.EntityManagerFactory]", ex);
}
else {
throw new IllegalStateException("Conflicting EntityManagerFactory interfaces - " +
"consider specifying the 'jpaVendorAdapter' or 'entityManagerFactoryInterface' property " +
"to select a specific EntityManagerFactory interface to proceed with", ex);
}
}
}
至此EntityManagerFactory构建完毕其实现为SessionFactoryImpl的代理类,通过LocalContainerEntityManagerFactoryBean的getObject方法给到Spring容器。
注:不要多此一举使用@Bean注解添加EntityManager的注入,原因在SpringDataJPA+Hibernate框架源码剖析(四)@PersistenceContext和@Autowired注入EntityManager的区别中会解释。
@Bean
public EntityManager entityManager(EntityManagerFactory entityManagerFactory){
// 此处EntityManager的实现为SessionImpl
return entityManagerFactory.createEntityManager();
}