我們要使用 Hibernate 的功能,首先需要讀取 Hibernate 的配置文件,根據配置啟動 Hibernate ,然后創建 SessionFactory。
創建 SessionFactory 的代碼很簡單,這也是我們要分析的代碼:
Configuration cfg = new Configuration().configure();
SessionFactory factory = cfg.buildSessionFactory();
接下來,就針對這兩行代碼進行分析。
1、初始化 Configuration
首先,我們來看看初始化 Configuration
實例的源碼中都做了些什么:
public Configuration() {
this( new BootstrapServiceRegistryBuilder().build() );
}
無參構造器調用了重載的構造器,接着看重載的構造器,Configuration.class 第121行:
public Configuration(BootstrapServiceRegistry serviceRegistry) {
this.bootstrapServiceRegistry = serviceRegistry;
this.metadataSources = new MetadataSources( serviceRegistry );
reset();
}
在這個構造器中,有個reset()
方法我們等下再看。我們先來看看傳入的參數 serviceRegistry
,以及初始化的兩個成員屬性:
BootstrapServiceRegistry
是個接口,翻譯過來是“啟動服務注冊器”,是 Hibernate 底層的的基礎服務注冊器。MetadataSources
元數據來源,構造器接收了BootstrapServiceRegistry
的實例
看一下這個構造器的源碼,MeatadataSources.class 第 77 行:
// 使用指定的服務注冊器實例創建一個 Metadata “元數據的源”
public MetadataSources(ServiceRegistry serviceRegistry) {
// 傳入的參數還只能是 BootstrapServiceRegistry 或 StandardServiceRegistry 類型的實例
if ( ! isExpectedServiceRegistryType( serviceRegistry ) ) {
LOG.debugf(
"Unexpected ServiceRegistry type [%s] encountered during building of MetadataSources; may cause " +
"problems later attempting to construct MetadataBuilder",
serviceRegistry.getClass().getName()
);
}
this.serviceRegistry = serviceRegistry;
this.xmlMappingBinderAccess = new XmlMappingBinderAccess( serviceRegistry );
}
好像看不太明白,那我們來看看這個 MetadataSource
類的說明注釋:
Entry point into working with sources of metadata information (mapping XML, annotations). Tell Hibernate about sources and then call buildMetadata() , or use getMetadataBuilder() to customize how sources are processed (naming strategies, etc).
加載元數據信息(一般是XML文件、注解中配置的映射)。Hibernate 加載該信息之后,通過調用 buildMetadata() 或者 getMetadataBuilder() 方法來確定整個 Hibernate 運行時環境的執行策略。
看到這里,可以認為 MetadataSource
的就是用來加載配置信息的。其實在 Metadata 中,就存儲了 ORM 的映射信息。
構造方法的最后一行代碼:
this.xmlMappingBinderAccess = new XmlMappingBinderAccess( serviceRegistry );
我們繼續跟蹤看看 XmlMappingBinderAccess
的構造方法做了些什么:
public XmlMappingBinderAccess(ServiceRegistry serviceRegistry) {
this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
// NOTE : 參數中的 boolean 值表示在加載 XML 文件時是否執行驗證。
// 在這里顯式指定為true,可以讓運行時的 JAXP(XML處理的Java API)和 JAXB(根據XML生成Java類)啟動速度更快,
// 如果不驗證 XML,可能會因為 XML 中的一些小錯誤而導致大麻煩。
this.mappingBinder
= new MappingBinder( serviceRegistry.getService( ClassLoaderService.class ), true );
}
好了,我們現在知道這行代碼是在做 XML 文件中綁定映射初始化相關的處理。
繼續回到 Configuration(BootstrapServiceRegistry serviceRegistry)
重載構造器中。
先簡單說明一下 Hibernate 中的 Service:
BootstrapServiceRegistry
接口的父接口是ServiceRegistry
,這個接口的父接口是Service
。
Hibernate 將所有的底層的功能都封裝為Service
注冊到 ServiceRegistry 中,需要的時候通過 getService() 方法獲取即可。
剛剛留下了一行 reset()
方法沒有看,我們現在來看看,Configuration.class 第 149 行:
protected void reset() {
implicitNamingStrategy = ImplicitNamingStrategyJpaCompliantImpl.INSTANCE;
physicalNamingStrategy = PhysicalNamingStrategyStandardImpl.INSTANCE;
namedQueries = new HashMap<String,NamedQueryDefinition>();
namedSqlQueries = new HashMap<String,NamedSQLQueryDefinition>();
sqlResultSetMappings = new HashMap<String, ResultSetMappingDefinition>();
namedEntityGraphMap = new HashMap<String, NamedEntityGraphDefinition>();
namedProcedureCallMap = new HashMap<String, NamedProcedureCallDefinition>( );
// 初始化 standardServiceRegistryBuilder 成員變量
standardServiceRegistryBuilder = new StandardServiceRegistryBuilder( bootstrapServiceRegistry );
entityTuplizerFactory = new EntityTuplizerFactory();
interceptor = EmptyInterceptor.INSTANCE;
properties = new Properties( );
properties.putAll( standardServiceRegistryBuilder.getSettings());
}
implicitNamingStrategy
和 physicalNamingStrategy
就是 Hibernate 的命名策略相關的實例:
implicitNamingStrategy
:隱式命名策略physicalNamingStrategy
:物理命名策略
命名策略有多種實現方式:Hibernate 標准,JPA 標准。可以調用 Configuration 對象的 setImplicitNamingStrategy()
和 setPhysicalNamingStrategy()
方法設置命名策略。
引用一張圖片,顯示了 Hibernate 5.x 中的命名策略的關系:
在這里先不對命名策略做太細化的研究,我們接着看下面幾行代碼中的 HashMap 實例分別代表什么:
- namedQuerys 讀取映射文件中
<query>
元素的內容或注解,該元素用於定義 HQL 語句 - namedSqlQueries 讀取映射文件中
<sql-query>
元素的內容或注解,該元素用於定義 SQL 語句 - sqlResultSetMappings 讀取映射文件中 SQL 查詢結果集的結構內容。
- namedEntityGraphMap 讀取映射文件或注解中的 EntityGraph 配置,是 JPA 2.1 的新規范
- namedProcedureCallMap 存儲過程相關的配置
我對 reset() 方法小結一下:重置初始化了另一些成員變量(囧)
至此,Configuration
的初始化過程就已經完成了。
接着調用 Configuration
對象的 configure()
方法,可以重載該方法指定配置文件的資源路徑。
我們先來看看無參的方法:
// 在程序的資源路徑下,讀取文件名為 hibernate.cfg.xml 映射配置文件
public Configuration configure() throws HibernateException {
return configure( StandardServiceRegistryBuilder.DEFAULT_CFG_RESOURCE_NAME );
}
再來看看有參的方法:
// 讀取符合 hibernate-configuration-3.0.dtd 文檔類型規范的配置文件
public Configuration configure(String resource) throws HibernateException {
standardServiceRegistryBuilder.configure( resource );
// ...
properties.putAll( standardServiceRegistryBuilder.getSettings() );
return this;
}
我們可以發現, configure() 方法內部調用了 standardServiceRegistryBuilder.configure( resource );
,如果我們只是使用 Configuration 對象,那么這個方法就沒有作用,這里我們還是追蹤了看一下,追蹤到類 StandardServiceRegistryBuilder
,看看其中的 configure() 做了什么處理:
// 從指定的資源位置,讀取 XML 文件獲取配置信息(常用)
public StandardServiceRegistryBuilder configure(String resourceName) {
return configure( configLoader.loadConfigXmlResource( resourceName ) );
}
// 指定 File 對象
public StandardServiceRegistryBuilder configure(File configurationFile) {
return configure( configLoader.loadConfigXmlFile( configurationFile ) );
}
// 可以獲取網絡上的指定路徑URL
public StandardServiceRegistryBuilder configure(URL url) {
return configure( configLoader.loadConfigXmlUrl( url ) );
}
// 有多個 cfg.xml 文件時,合並它們
public StandardServiceRegistryBuilder configure(LoadedConfig loadedConfig) {
aggregatedCfgXml.merge( loadedConfig );
settings.putAll( loadedConfig.getConfigurationValues() );
return this;
}
最終返回了 StandardServiceRegistryBuilder
對象,這個對象用作 Hibernate 5.x 中創建 SessionFactory。關於 Hibernate 5.x 的創建方式,將在另一篇文章中講解。
2、創建 SessionFactory
接下來,看我們要分析的第二行代碼:
SessionFactory factory = cfg.buildSessionFactory();
調用 Configuration 對象的 buildSessionFactory()
方法。我們進到這個方法看看里面是什么:
// 使用當前 configuration 配置對象中的配置信息創建一個 SessionFactory 實例,該實例被創建后就不會再改變
// 此后再對 configuration 做修改也不會影響到已創建的 SessionFactory 實例
public SessionFactory buildSessionFactory() throws HibernateException {
log.debug( "Building session factory using internal StandardServiceRegistryBuilder" );
// ----- 1、使用 properties 重置配置屬性 -----
standardServiceRegistryBuilder.applySettings( properties );
return buildSessionFactory( standardServiceRegistryBuilder.build() );
}
public SessionFactory buildSessionFactory(ServiceRegistry serviceRegistry) throws HibernateException {
log.debug( "Building session factory using provided StandardServiceRegistry" );
// ----- 2、創建 MetadataBuilder ,然后做一些配置工作 -----
final MetadataBuilder metadataBuilder = metadataSources
.getMetadataBuilder( (StandardServiceRegistry) serviceRegistry );
// 設置默認的隱式命名策略
if ( implicitNamingStrategy != null ) {
metadataBuilder.applyImplicitNamingStrategy( implicitNamingStrategy );
}
// 設置默認的物理命名策略
if ( physicalNamingStrategy != null ) {
metadataBuilder.applyPhysicalNamingStrategy( physicalNamingStrategy );
}
// 設置共享緩存模式
if ( sharedCacheMode != null ) {
metadataBuilder.applySharedCacheMode( sharedCacheMode );
}
if ( !typeContributorRegistrations.isEmpty() ) {
for ( TypeContributor typeContributor : typeContributorRegistrations ) {
metadataBuilder.applyTypes( typeContributor );
}
}
if ( !basicTypes.isEmpty() ) {
for ( BasicType basicType : basicTypes ) {
metadataBuilder.applyBasicType( basicType );
}
}
if ( sqlFunctions != null ) {
for ( Map.Entry<String, SQLFunction> entry : sqlFunctions.entrySet() ) {
metadataBuilder.applySqlFunction( entry.getKey(), entry.getValue() );
}
}
if ( auxiliaryDatabaseObjectList != null ) {
for ( AuxiliaryDatabaseObject auxiliaryDatabaseObject : auxiliaryDatabaseObjectList ) {
metadataBuilder.applyAuxiliaryDatabaseObject( auxiliaryDatabaseObject );
}
}
if ( attributeConverterDefinitionsByClass != null ) {
for ( AttributeConverterDefinition attributeConverterDefinition : attributeConverterDefinitionsByClass.values() ) {
metadataBuilder.applyAttributeConverter( attributeConverterDefinition );
}
}
// ----- 3、使用 MetadataBuilder 創建 Metadata 實例 -----
final Metadata metadata = metadataBuilder.build();
// 使用 Metadata 對象的 getSessionFactoryBuilder() 創建 SessionFactoryBuilder
final SessionFactoryBuilder sessionFactoryBuilder =
metadata.getSessionFactoryBuilder();
if ( interceptor != null && interceptor != EmptyInterceptor.INSTANCE ) {
sessionFactoryBuilder.applyInterceptor( interceptor );
}
if ( getSessionFactoryObserver() != null ) {
// 為 SessionFactory 添加觀察者 Observers
sessionFactoryBuilder.addSessionFactoryObservers( getSessionFactoryObserver() );
}
if ( getEntityNotFoundDelegate() != null ) {
sessionFactoryBuilder.applyEntityNotFoundDelegate( getEntityNotFoundDelegate() );
}
if ( getEntityTuplizerFactory() != null ) {
sessionFactoryBuilder.applyEntityTuplizerFactory( getEntityTuplizerFactory() );
}
if ( getCurrentTenantIdentifierResolver() != null ) {
sessionFactoryBuilder.applyCurrentTenantIdentifierResolver( getCurrentTenantIdentifierResolver() );
}
// 4、創建並返回 SessionFactory 實例
return sessionFactoryBuilder.build();
}
buildSessionFactory()
方法的內容比較多,但是主要就是3個核心步驟:
- 創建 MetadataBuilder ,然后做一些配置工作
- 使用 MetadataBuilder 創建 Metadata 實例,metadata 中存儲了所有的 ORM 映射信息
- 創建並返回 SessionFactory 實例
至此,Hibernate 5.x 創建 SessionFactory 的源碼全部走完。