JPA,Spring中 Hibernate对JPA实现 如何初始化和获得数据源分析
通过调试,我们发现是 spring启动中,hibernate会装载和初始化 全局配置, 其实就是个 Map。 在Map中 他会初始化org.hibernate.cfg.AvailableSettings#DATASOURCE 的key 作为 map里数据源的key。 数据源初始化代码 位于 org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl#normalizeDataAccess : private void normalizeDataAccess( HashMap<?, ?> integrationSettingsCopy, MergedSettings mergedSettings, PersistenceUnitDescriptor persistenceUnit) { if ( dataSource != null ) { applyDataSource( dataSource, // we don't explicitly know null, integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } if ( integrationSettingsCopy.containsKey( DATASOURCE ) ) { final Object dataSourceRef = integrationSettingsCopy.remove( DATASOURCE ); if ( dataSourceRef != null ) { applyDataSource( dataSourceRef, null, integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } } if ( integrationSettingsCopy.containsKey( JPA_JTA_DATASOURCE ) ) { final Object dataSourceRef = integrationSettingsCopy.remove( JPA_JTA_DATASOURCE ); if ( dataSourceRef != null ) { applyDataSource( dataSourceRef, true, integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } } if ( integrationSettingsCopy.containsKey( JPA_NON_JTA_DATASOURCE ) ) { final Object dataSourceRef = integrationSettingsCopy.remove( JPA_NON_JTA_DATASOURCE ); applyDataSource( dataSourceRef, false, integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } if ( integrationSettingsCopy.containsKey( URL ) ) { // these have precedence over the JPA ones final Object integrationJdbcUrl = integrationSettingsCopy.get( URL ); if ( integrationJdbcUrl != null ) { //noinspection unchecked applyJdbcSettings( integrationJdbcUrl, NullnessHelper.coalesceSuppliedValues( () -> ConfigurationHelper.getString( DRIVER, integrationSettingsCopy ), () -> ConfigurationHelper.getString( JPA_JDBC_DRIVER, integrationSettingsCopy ), () -> ConfigurationHelper.getString( DRIVER, mergedSettings.configurationValues ), () -> ConfigurationHelper.getString( JPA_JDBC_DRIVER, mergedSettings.configurationValues ) ), integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } } if ( integrationSettingsCopy.containsKey( JPA_JDBC_URL ) ) { final Object integrationJdbcUrl = integrationSettingsCopy.get( JPA_JDBC_URL ); if ( integrationJdbcUrl != null ) { //noinspection unchecked applyJdbcSettings( integrationJdbcUrl, NullnessHelper.coalesceSuppliedValues( () -> ConfigurationHelper.getString( JPA_JDBC_DRIVER, integrationSettingsCopy ), () -> ConfigurationHelper.getString( JPA_JDBC_DRIVER, mergedSettings.configurationValues ) ), integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } } if ( persistenceUnit.getJtaDataSource() != null ) { applyDataSource( persistenceUnit.getJtaDataSource(), true, integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } if ( persistenceUnit.getNonJtaDataSource() != null ) { applyDataSource( persistenceUnit.getNonJtaDataSource(), false, integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } if ( mergedSettings.configurationValues.containsKey( URL ) ) { final Object url = mergedSettings.configurationValues.get( URL ); if ( url != null && ( ! ( url instanceof String ) || StringHelper.isNotEmpty( (String) url ) ) ) { applyJdbcSettings( url, ConfigurationHelper.getString( DRIVER, mergedSettings.configurationValues ), integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } } if ( mergedSettings.configurationValues.containsKey( JPA_JDBC_URL ) ) { final Object url = mergedSettings.configurationValues.get( JPA_JDBC_URL ); if ( url != null && ( ! ( url instanceof String ) || StringHelper.isNotEmpty( (String) url ) ) ) { applyJdbcSettings( url, ConfigurationHelper.getString( JPA_JDBC_DRIVER, mergedSettings.configurationValues ), integrationSettingsCopy, mergedSettings ); // EARLY EXIT!! return; } } // any other conditions to account for? } 通过代码可以看出 他会优先几个 key,看是否已经有了,有就沿用这些key里的数据源。 我的项目目前都没有,代码往下走,到了 if ( persistenceUnit.getNonJtaDataSource() != null ) { 这一行, 发现在 org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor#getNonJtaDataSource 获取了数据源: 转而调用了javax.persistence.spi.PersistenceUnitInfo#getNonJtaDataSource : 发现真正的实现类是:org.springframework.orm.jpa.persistenceunit.SpringPersistenceUnitInfo 的getNonJtaDataSource 方法。 然后最终调用了 :org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo#getNonJtaDataSource 这个方法返回了 这个类的实例变量 org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo#nonJtaDataSource , 所以我们继续看 实例变量是如何初始化的: 最终发现 是org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration 初始化的, 而他是由org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration 导入的。 然后发现 最后DataSource来自于 spring boot autoconfig包的org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration 类, HibernateJpaConfiguration 直接继承的他, 默认的DataSource对象也是JpaBaseConfiguration 实例字段。 org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration#dataSource 而这个字段则是直接通过 类构造方法 让spring自动ioc的。 题外话:关于 JPA实现类似mybatis的动态效果,可以参考下大佬的开源: https://gitee.com/it00021hot/fenix