Spring Data之EntityManagerFactory建立及原始碼分析
背景
在Spring Data之JPA開篇中可以看到Spring Boot的啟動日誌,先是建立了HikariDataSource,然後緊接著構建了EntityManagerFactory
2018-10-25 09:32:20.645 INFO 37469 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2018-10-25 09:32:20.791 INFO 37469 --- [ main] com.zaxxer.hikari. HikariDataSource : HikariPool-1 - Start completed.
2018-10-25 09:32:20.846 INFO 37469 --- [ main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
其中HikariDataSource的建立在Spring Data之DataSource建立及原始碼分析中進行了介紹,這篇文章我們就來探尋一下EntityManagerFactory是如何自動創建出來的。
JPA規範
首先有必要了解一下JPA規範(JSR 338)以便更好的理解EntityManagerFactory的建立過程。
JSR 338主要定義瞭如何通過普通的Java domain進行關係資料庫的操作及對映,其中主要概念包含如下:
- Entity
- 必須是頂級類
- @Entity註解的類
- 必須有一個無參的public 或 protected的構造方法
- 不能是final類,且不能有final方法或final變數
- 一個Entity類通常與資料庫的一張表進行對應
- 一個Entity例項表現為資料庫的一條資料
- 對Entity的操作即對資料庫的操作
- 生命週期包含初始、託管、釋放、消亡
- EntityManager
- 對Entity持久化操作的主要物件
- 通過EntityManagerFactory獲取例項
- 一個例項代表一個數據庫連線
- 每個執行緒擁有自己的EntityManager例項
- 主要方法有persist、remove、merge、createQuery、find
- 可使用@PersistenceContext注入
- EntityManagerFactory
- 建立EntityManager的工廠
- EntityManagerFactory的建立成本很高,對於給定的資料庫,系統應該只建立一個與之關聯的Factory
- 可使用@PersistenceUnit注入
- EntityTransaction
- 表示資料庫事務,在增、刪、改時使用
- 可通過EntityManager.getTransaction()獲取
- Persistence Context
- 維護一組託管狀態的Entity例項
- 與EntityManager是相關聯的
- Persistence Unit
- 一組Entity及相關設定的邏輯單元
- 定義建立EntityManagerFactory所需要的引數
- 通過persistence.xml定義或者通過一個PersistenceUnitInfo物件
總結一下,通過Persistence Unit建立EntityManagerFactory,再通過EntityManagerFactory獲取EntityManager。下面我們就按照這個方向進行原始碼分析。
自動配置
同DataSource一樣,EntityManagerFactory的建立也是通過一些列@Conditional的註解最終找到Hibernate的實現。我們先看下自動配置的入口類HibernateJpaAutoConfiguration
@Configuration
//先校驗是否存在LocalContainerEntityManagerFactoryBean
//該類是spring-orm包中的類,從名稱上看就知道是跟EntityManagerFactory的建立有關的
//要使用JPA,EntityManager自然也是要存在的
@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EntityManager.class })
//自定義的校驗類,校驗是否存在CLASS_NAMES中的類
@Conditional(HibernateEntityManagerCondition.class)
//在application.properties中配置的spring.jpa開頭的設定,會注入到JpaProperties中
//換句話說在spring.jpa能設定什麼,要看JpaProperties有什麼屬性
@EnableConfigurationProperties(JpaProperties.class)
//這個設定很關鍵,意思是要在DataSource之後再建立,因為JPA會用到DataSource
@AutoConfigureAfter({ DataSourceAutoConfiguration.class })
//上面的校驗都滿足後,則進入HibernateJpaConfiguration
@Import(HibernateJpaConfiguration.class)
public class HibernateJpaAutoConfiguration {
@Order(Ordered.HIGHEST_PRECEDENCE + 20)
static class HibernateEntityManagerCondition extends SpringBootCondition {
private static final String[] CLASS_NAMES = {
"org.hibernate.ejb.HibernateEntityManager",
"org.hibernate.jpa.HibernateEntityManager" };
/**
* 通過ClassUtils.isPresent檢查是否存在CLASS_NAMES中指定的類
*/
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
ConditionMessage.Builder message = ConditionMessage
.forCondition("HibernateEntityManager");
for (String className : CLASS_NAMES) {
if (ClassUtils.isPresent(className, context.getClassLoader())) {
return ConditionOutcome
.match(message.found("class").items(Style.QUOTE, className));
}
}
return ConditionOutcome.noMatch(message.didNotFind("class", "classes")
.items(Style.QUOTE, Arrays.asList(CLASS_NAMES)));
}
}
}
主要邏輯已在程式碼中添加註釋說明,接下來就看下@Import的HibernateJpaConfiguration
@Configuration
@ConditionalOnSingleCandidate(DataSource.class)
class HibernateJpaConfiguration extends JpaBaseConfiguration {
//省略。。。
@Override
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
return new HibernateJpaVendorAdapter();
}
//省略。。。
}
省略了一些不重要的程式碼,只留下createJpaVendorAdapter方法。再接著看父類JpaBaseConfiguration
@EnableConfigurationProperties(JpaProperties.class)
@Import(DataSourceInitializedPublisher.Registrar.class)
public abstract class JpaBaseConfiguration implements BeanFactoryAware {
private final DataSource dataSource;
private final JpaProperties properties;
private final JtaTransactionManager jtaTransactionManager;
private final TransactionManagerCustomizers transactionManagerCustomizers;
private ConfigurableListableBeanFactory beanFactory;
protected JpaBaseConfiguration(DataSource dataSource, JpaProperties properties,
ObjectProvider<JtaTransactionManager> jtaTransactionManager,
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
this.dataSource = dataSource;
this.properties = properties;
this.jtaTransactionManager = jtaTransactionManager.getIfAvailable();
this.transactionManagerCustomizers = transactionManagerCustomizers
.getIfAvailable();
}
@Bean
@ConditionalOnMissingBean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
if (this.transactionManagerCustomizers != null) {
this.transactionManagerCustomizers.customize(transactionManager);
}
return transactionManager;
}
@Bean
@ConditionalOnMissingBean
public JpaVendorAdapter jpaVendorAdapter() {
AbstractJpaVendorAdapter adapter = createJpaVendorAdapter();
adapter.setShowSql(this.properties.isShowSql());
adapter.setDatabase(this.properties.determineDatabase(this.dataSource));
adapter.setDatabasePlatform(this.properties.getDatabasePlatform());
adapter.setGenerateDdl(this.properties.isGenerateDdl());
return adapter;
}
@Bean
@ConditionalOnMissingBean
public EntityManagerFactoryBuilder entityManagerFactoryBuilder(
JpaVendorAdapter jpaVendorAdapter,
ObjectProvider<PersistenceUnitManager> persistenceUnitManager) {
EntityManagerFactoryBuilder builder = new EntityManagerFactoryBuilder(
jpaVendorAdapter, this.properties.getProperties(),
persistenceUnitManager.getIfAvailable());
builder.setCallback(getVendorCallback());
return builder;
}
@Bean
@Primary
@ConditionalOnMissingBean({ LocalContainerEntityManagerFactoryBean.class,
EntityManagerFactory.class })
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
EntityManagerFactoryBuilder factoryBuilder) {
Map<String, Object> vendorProperties = getVendorProperties();
customizeVendorProperties(vendorProperties);
return factoryBuilder.dataSource(this.dataSource).packages(getPackagesToScan())
.properties(vendorProperties).mappingResources(getMappingResources())
.jta(isJta()).build();
}
protected abstract AbstractJpaVendorAdapter createJpaVendorAdapter();
}
可以看到該類有4個@Bean註解的方法,咱們按順序分析
-
transactionManager
建立JPA事務的管理器 -
jpaVendorAdapter
JpaVendorAdapter是一個介面,裡面有一個方法是getPersistenceProvider,而PersistenceProvider是JPA規範中定義的建立EntityManagerFactory的介面方法。
createJpaVendorAdapter的實現是在HibernateJpaConfiguration中返回的是 HibernateJpaVendorAdapter.public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter{ private final HibernateJpaDialect jpaDialect = new HibernateJpaDialect(); private final PersistenceProvider persistenceProvider; private final Class<? extends EntityManagerFactory> entityManagerFactoryInterface; private final Class<? extends EntityManager> entityManagerInterface; /** * 明確指明瞭persistenceProvider的實現是SpringHibernateJpaPersistenceProvider */ @SuppressWarnings("deprecation") public HibernateJpaVendorAdapter() { this.persistenceProvider = new SpringHibernateJpaPersistenceProvider(); this.entityManagerFactoryInterface = org.hibernate.jpa.HibernateEntityManagerFactory.class; this.entityManagerInterface = org.hibernate.jpa.HibernateEntityManager.class; } }
/** * 繼承了Hibernate的PersistenceProvider */ class SpringHibernateJpaPersistenceProvider extends HibernatePersistenceProvider{ /** * 重要方法,呼叫了Hibernate的EntityManagerFactoryBuilderImpl,通過build創建出了EntityManagerFactory */ public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map properties) { final List<String> mergedClassesAndPackages = new ArrayList<>(info.getManagedClassNames()); if (info instanceof SmartPersistenceUnitInfo) { mergedClassesAndPackages.addAll(((SmartPersistenceUnitInfo) info).getManagedPackages()); } return new EntityManagerFactoryBuilderImpl( new PersistenceUnitInfoDescriptor(info) { @Override public List<String> getManagedClassNames() { return mergedClassesAndPackages; } }, properties).build(); } }
-
entityManagerFactoryBuilder
建造者模式,將需要的原料都準備好 -
entityManagerFactory
LocalContainerEntityManagerFactoryBean就是啟動日誌中打印出*Building JPA container EntityManagerFactory for persistence unit ‘default’*的類。
該類及其父類AbstractEntityManagerFactoryBean包含了建立EntityManagerFactory的所有元素,前面的步驟都是在為LocalContainerEntityManagerFactoryBean的屬性準備資料賦值public class LocalContainerEntityManagerFactoryBean extends AbstractEntityManagerFactoryBean implements ResourceLoaderAware, LoadTimeWeaverAware { /** *根據provider(前面提到的SpringHibernateJpaPersistenceProvider)建立EntityManagerFactory */ protected EntityManagerFactory createNativeEntityManagerFactory() throws PersistenceException { Assert.state(this.persistenceUnitInfo != null, "PersistenceUnitInfo not initialized"); PersistenceProvider provider = getPersistenceProvider(); if (provider == null) { String providerClassName = this.persistenceUnitInfo.getPersistenceProviderClassName(); if (providerClassName == null) { throw new IllegalArgumentException( "No PersistenceProvider specified in EntityManagerFactory configuration, " + "and chosen PersistenceUnitInfo does not specify a provider class name either"); } Class<?> providerClass = ClassUtils.resolveClassName(providerClassName, getBeanClassLoader()); provider = (PersistenceProvider) BeanUtils.instantiateClass(providerClass); } if (logger.isInfoEnabled()) { logger.info("Building JPA container EntityManagerFactory for persistence unit '" + this.persistenceUnitInfo.getPersistenceUnitName() + "'"); } EntityManagerFactory emf = provider.createContainerEntityManagerFactory(this.persistenceUnitInfo, getJpaPropertyMap()); postProcessEntityManagerFactory(emf, this.persistenceUnitInfo); return emf; } }
需要注意的是AbstractEntityManagerFactoryBean有兩個EntityManagerFactory型別的屬性,一個是通過PersistenceProvider獲取的原生物件,另一個是Spring建立的代理物件ManagedEntityManagerFactoryInvocationHandler,它的目的是為了攔截EntityManager的建立,至少為什麼要代理,下篇文件會進行分析。
結束語
到這裡EntityManagerFactory就創建出來了,總的來說整個過程是遵循JPA規範定義的介面的,例如SpringHibernateJpaPersistenceProvider實現的createContainerEntityManagerFactory方法。只不過Spring作為骨幹框架,使用了很多中間物件和過程。
最後用一張類圖,再串一下建立的過程
-
首先以左下角的HibernateJpaAutoConfiguration為入口,經過@Conditional的判斷,@Import進入HibernateJpaConfiguration
-
在HibernateJpaConfiguration中依賴類HibernateJpaVendorAdapter,而HibernateJpaVendorAdapter又依賴了SpringHibernateJpaPersistenceProvider,PersistenceProvider的具體實現就確定了
-
在JpaBaseConfiguration中通過EntityManagerFactoryBuilder創建出了LocalContainerEntityManagerFactoryBean,該類是整個結構的紐帶。可以看到它關聯了PersistenceProvider和PersistenceUnitManager,而PersistenceUnitManager是產生PersistenceUnitInfo的,PersistenceProvider和PersistenceUnitInfo是createEntityFactory的兩個必要物件
-
最後在LocalContainerEntityManagerFactoryBean中呼叫SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory創建出了EntityManagerFactory
那麼EntityManagerFactory創建出來後有什麼用呢,當然是用來獲取EntityManager,下篇文章我們繼續分析EntityManager的建立過程。