SpringDataJPA+Hibernate框架源码剖析(二)框架整合 之 EntityManagerFactory的构建

SpringDataJPA+Hibernate框架源码剖析系列文章:

  1. SpringDataJPA+Hibernate框架源码剖析(一)框架介绍
  2. SpringDataJPA+Hibernate框架源码剖析(二)框架整合 之 EntityManagerFactory的构建
  3. SpringDataJPA+Hibernate框架源码剖析(三)框架整合 之 Repository接口实现的生成
  4. SpringDataJPA+Hibernate框架源码剖析(四)框架整合 之 事务管理器的构建(包括spring的事务机制)
  5. SpringDataJPA+Hibernate框架源码剖析(五)框架整合 之 SpringBoot整合JPA剖析
  6. 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构造函数如下图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tp5NL9x6-1645446531125)(/Users/yangxiaofei/Library/Application Support/typora-user-images/image-20220104171456279.png)]

一个四个入参前两个必填后两个可为空,后面步骤用到是再详细介绍

  1. jpaVendorAdapter:JPA适配器,具体ORM框架需要具体实现类,包含方言和具体ORM框架的一些配置如:showSql、databasePlatform
  2. jpaProperties: jap的配置信息如:hibernate.show_sql、hibernate.dialect
  3. persistenceUnitManager:persistence.xml文件解析器,可以解析管理多个持久化单元
  4. 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;
	}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Frradgd0-1645446531126)(/Users/yangxiaofei/Library/Application Support/typora-user-images/image-20220105154223742.png)]

至此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();
    }
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

躺平程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值