接學習四,下來就是呼叫configuration的buildSessionFactory方法來建立一個sessionFactory了,具體程式碼如下:
public SessionFactory buildSessionFactory(ServiceRegistry serviceRegistry) throws HibernateException {
LOG.debugf( "Preparing to build session factory with filters : %s", filterDefinitions );
//註冊型別,包含資料庫方言
buildTypeRegistrations( serviceRegistry );
//二次傳遞編譯,包含註解處理
secondPassCompile();
if ( !metadataSourceQueue.isEmpty() ) {
LOG.incompleteMappingMetadataCacheProcessing();
}
//校驗所配置的對映類與hbm配置檔案中的屬性是否一致
validate();
//校驗全域性配置屬性
Environment.verifyProperties( properties );
Properties copy = new Properties();
copy.putAll( properties );
//拷貝一份配置,處理佔位符
ConfigurationHelper.resolvePlaceHolders( copy );
//通過配置的屬性和註冊的服務建立一個設定
Settings settings = buildSettings( copy, serviceRegistry );
//通過註冊的服務,對映檔案,設定,以及一個session工廠的觀察者//(用於監視會話工廠狀態)來建立一個會話工廠的實現
return new SessionFactoryImpl(
this,
mapping,
serviceRegistry,
settings,
sessionFactoryObserver
);
}
下面看一下上述的secondPassCompile()二次傳遞編譯方法secondPassCompile()的具體程式碼:
protected void secondPassCompile () throws MappingException {
LOG.trace( "Starting secondPassCompile() processing" );
// TEMPORARY
// Ensure the correct ClassLoader is used in commons-annotations.
//獲取當前執行緒中所使用的classLoader,便於處理結束後,將該classloader在設定為當//前執行緒所使用的類載入器,僅用於保留物件
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
//獲取ClassLoaderHelper中的上下文類載入器並設定到當前執行緒,確保所使用的類//載入器,檢視實際程式碼,發現其實返回的還是當前執行緒所使用的上下文載入器,但//ClassLoaderHelper註釋中說明該屬性可以通過客戶自定義注入來進行替換,而且在//Hibernate5中將被替換為其他方式,具體參見ClassLoaderHelper原始碼 Thread.currentThread().setContextClassLoader( ClassLoaderHelper.getContextClassLoader() );
//process default values first,第一次處理的時候需要設定一下預設值
{
if ( !isDefaultProcessed ) {
//use global delimiters if orm.xml declare it
Map defaults = reflectionManager.getDefaults();
final Object isDelimited = defaults.get( "delimited-identifier" );
if ( isDelimited != null && isDelimited == Boolean.TRUE ) {
getProperties().put( Environment.GLOBALLY_QUOTED_IDENTIFIERS, "true" );
}
// Set default schema name if orm.xml declares it.
final String schema = (String) defaults.get( "schema" );
if ( StringHelper.isNotEmpty( schema ) ) {
getProperties().put( Environment.DEFAULT_SCHEMA, schema );
}
// Set default catalog name if orm.xml declares it.
final String catalog = (String) defaults.get( "catalog" );
if ( StringHelper.isNotEmpty( catalog ) ) {
getProperties().put( Environment.DEFAULT_CATALOG, catalog );
}
//註解繫結
AnnotationBinder.bindDefaults( createMappings() );
isDefaultProcessed = true;
}
}
// process metadata queue
{
metadataSourceQueue.syncAnnotatedClasses();
metadataSourceQueue.processMetadata( determineMetadataSourcePrecedence() );
}
try {
inSecondPass = true;
processSecondPassesOfType( PkDrivenByDefaultMapsIdSecondPass.class );
processSecondPassesOfType( SetSimpleValueTypeSecondPass.class );
processSecondPassesOfType( CopyIdentifierComponentSecondPass.class );
processFkSecondPassInOrder();
processSecondPassesOfType( CreateKeySecondPass.class );
processSecondPassesOfType( SecondaryTableSecondPass.class );
originalSecondPassCompile();
inSecondPass = false;
}
catch ( RecoverableException e ) {
//the exception was not recoverable after all
throw ( RuntimeException ) e.getCause();
}
// process cache queue,快取佇列處理
{
for ( CacheHolder holder : caches ) {
if ( holder.isClass ) {
applyCacheConcurrencyStrategy( holder );
}
else {
applyCollectionCacheConcurrencyStrategy( holder );
}
}
caches.clear();
}
//唯一約束處理
for ( Map.Entry<Table, List<UniqueConstraintHolder>> tableListEntry : uniqueConstraintHoldersByTable.entrySet() ) {
final Table table = tableListEntry.getKey();
final List<UniqueConstraintHolder> uniqueConstraints = tableListEntry.getValue();
for ( UniqueConstraintHolder holder : uniqueConstraints ) {
buildUniqueKeyFromColumnNames( table, holder.getName(), holder.getColumns() );
}
}
//恢復當前執行緒的上下文類載入器為初始上下文類載入器
Thread.currentThread().setContextClassLoader( tccl );
}
建立sessionFactory所使用的建構函式程式碼:
public SessionFactoryImpl(
final Configuration cfg,
Mapping mapping,
ServiceRegistry serviceRegistry,
Settings settings,
SessionFactoryObserver observer) throws HibernateException {
LOG.debug( "Building session factory" );
//session工廠的設定項
sessionFactoryOptions = new SessionFactoryOptions() {
private EntityNotFoundDelegate entityNotFoundDelegate;
@Override
public Interceptor getInterceptor() {
return cfg.getInterceptor();
}
@Override
public EntityNotFoundDelegate getEntityNotFoundDelegate() {
if ( entityNotFoundDelegate == null ) {
if ( cfg.getEntityNotFoundDelegate() != null ) {
entityNotFoundDelegate = cfg.getEntityNotFoundDelegate();
}
else {
entityNotFoundDelegate = new EntityNotFoundDelegate() {
public void handleEntityNotFound(String entityName, Serializable id) {
throw new ObjectNotFoundException( id, entityName );
}
};
}
}
return entityNotFoundDelegate;
}
};
this.settings = settings;
this.properties = new Properties();
this.properties.putAll( cfg.getProperties() );
this.serviceRegistry = serviceRegistry.getService( SessionFactoryServiceRegistryFactory.class ).buildServiceRegistry(
this,
cfg
);
//jdbc服務
this.jdbcServices = this.serviceRegistry.getService( JdbcServices.class );
//方言
this.dialect = this.jdbcServices.getDialect();
//快取訪問服務
this.cacheAccess = this.serviceRegistry.getService( CacheImplementor.class );
final RegionFactory regionFactory = cacheAccess.getRegionFactory();
//sql函式註冊,將配置中的自定義方法及制定資料庫方言中的方法註冊到一個//以方法名稱為key,對應的方言所對英的SQLFunction介面實現類的 Map中,
this.sqlFunctionRegistry = new SQLFunctionRegistry( getDialect(), cfg.getSqlFunctions() );
//如果指定的觀察者不為空,將其新增到當前的觀察者鏈中//SessionFactoryObserverChain
if ( observer != null ) {
this.observer.addObserver( observer );
}
this.typeResolver = cfg.getTypeResolver().scope( this );
this.typeHelper = new TypeLocatorImpl( typeResolver );
//過濾器
this.filters = new HashMap<String, FilterDefinition>();
this.filters.putAll( cfg.getFilterDefinitions() );
LOG.debugf( "Session factory constructed with filter configurations : %s", filters );
LOG.debugf( "Instantiating session factory with properties: %s", properties );
//查詢計劃快取
this.queryPlanCache = new QueryPlanCache( this );
// todo : everything above here consider implementing as standard SF service. specifically: stats, caches, types, function-reg
//內部類,用於定義一個攔截器的SessionFactory觀察者
//攔截器介面可以用於在對持久類進行載入、編輯、更新等操作前進行處理,可//以用於記錄操作資訊
class IntegratorObserver implements SessionFactoryObserver {
private ArrayList<Integrator> integrators = new ArrayList<Integrator>();
@Override
public void sessionFactoryCreated(SessionFactory factory) {
}
@Override
//sessionFactory關閉時,呼叫每個攔截器的回撥方法disintegrate
public void sessionFactoryClosed(SessionFactory factory) {
for ( Integrator integrator : integrators ) {
integrator.disintegrate( SessionFactoryImpl.this, SessionFactoryImpl.this.serviceRegistry );
}
}
}
//攔截器觀察著
final IntegratorObserver integratorObserver = new IntegratorObserver();
//將攔截器的觀察者加入當前的觀察者鏈中
this.observer.addObserver( integratorObserver );
//獲取攔截器對應的服務類,設定攔截
for ( Integrator integrator : serviceRegistry.getService( IntegratorService.class ).getIntegrators() ) {
integrator.integrate( cfg, this, this.serviceRegistry );
integratorObserver.integrators.add( integrator );
}
//Generators:
//標示符生成器
identifierGenerators = new HashMap();
//獲取當前配置中的所有對映類
Iterator classes = cfg.getClassMappings();
while ( classes.hasNext() ) {
PersistentClass model = (PersistentClass) classes.next();
//如果當前對映類的定義不是繼承的,則根據其定義進行設定
if ( !model.isInherited() ) {
IdentifierGenerator generator = model.getIdentifier().createIdentifierGenerator(
cfg.getIdentifierGeneratorFactory(),
getDialect(),
settings.getDefaultCatalogName(),
settings.getDefaultSchemaName(),
(RootClass) model
);
//設定持久類的標示符生成器
identifierGenerators.put( model.getEntityName(), generator );
}
}
///////////////////////////////////////////////////////////////////////
// Prepare persisters and link them up with their cache
// region/access-strategy
//獲取設定中的快取範圍
final String cacheRegionPrefix = settings.getCacheRegionPrefix() == null ? "" : settings.getCacheRegionPrefix() + ".";
//持久化工廠服務
final PersisterFactory persisterFactory = serviceRegistry.getService( PersisterFactory.class );
//持久類
entityPersisters = new HashMap();
Map entityAccessStrategies = new HashMap();
Map<String,ClassMetadata> classMeta = new HashMap<String,ClassMetadata>();
//獲取所有對映類
classes = cfg.getClassMappings();
while ( classes.hasNext() ) {
final PersistentClass model = (PersistentClass) classes.next();
model.prepareTemporaryTables( mapping, getDialect() );
final String cacheRegionName = cacheRegionPrefix + model.getRootClass().getCacheRegionName();
// cache region is defined by the root-class in the hierarchy...
EntityRegionAccessStrategy accessStrategy = ( EntityRegionAccessStrategy ) entityAccessStrategies.get( cacheRegionName );
if ( accessStrategy == null && settings.isSecondLevelCacheEnabled() ) {
final AccessType accessType = AccessType.fromExternalName( model.getCacheConcurrencyStrategy() );
if ( accessType != null ) {
LOG.tracef( "Building shared cache region for entity data [%s]", model.getEntityName() );
EntityRegion entityRegion = regionFactory.buildEntityRegion( cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) );
accessStrategy = entityRegion.buildAccessStrategy( accessType );
entityAccessStrategies.put( cacheRegionName, accessStrategy );
cacheAccess.addCacheRegion( cacheRegionName, entityRegion );
}
}
NaturalIdRegionAccessStrategy naturalIdAccessStrategy = null;
if ( model.hasNaturalId() && model.getNaturalIdCacheRegionName() != null ) {
final String naturalIdCacheRegionName = cacheRegionPrefix + model.getNaturalIdCacheRegionName();
naturalIdAccessStrategy = ( NaturalIdRegionAccessStrategy ) entityAccessStrategies.get( naturalIdCacheRegionName );
if ( naturalIdAccessStrategy == null && settings.isSecondLevelCacheEnabled() ) {
final CacheDataDescriptionImpl cacheDataDescription = CacheDataDescriptionImpl.decode( model );
NaturalIdRegion naturalIdRegion = null;
try {
naturalIdRegion = regionFactory.buildNaturalIdRegion( naturalIdCacheRegionName, properties,
cacheDataDescription );
}
catch ( UnsupportedOperationException e ) {
LOG.warnf(
"Shared cache region factory [%s] does not support natural id caching; " +
"shared NaturalId caching will be disabled for not be enabled for %s",
regionFactory.getClass().getName(),
model.getEntityName()
);
}
if (naturalIdRegion != null) {
naturalIdAccessStrategy = naturalIdRegion.buildAccessStrategy( regionFactory.getDefaultAccessType() );
entityAccessStrategies.put( naturalIdCacheRegionName, naturalIdAccessStrategy );
cacheAccess.addCacheRegion( naturalIdCacheRegionName, naturalIdRegion );
}
}
}
//根據上述配置生成一個實體對映
EntityPersister cp = persisterFactory.createEntityPersister(
model,
accessStrategy,
naturalIdAccessStrategy,
this,
mapping
);
//以實體對映的名稱為key,將對應的持久類加入entityPersisters
entityPersisters.put( model.getEntityName(), cp );
classMeta.put( model.getEntityName(), cp.getClassMetadata() );
}
this.classMetadata = Collections.unmodifiableMap(classMeta);
Map<String,Set<String>> tmpEntityToCollectionRoleMap = new HashMap<String,Set<String>>();
collectionPersisters = new HashMap<String,CollectionPersister>();
Map<String,CollectionMetadata> tmpCollectionMetadata = new HashMap<String,CollectionMetadata>();
Iterator collections = cfg.getCollectionMappings();
while ( collections.hasNext() ) {
Collection model = (Collection) collections.next();
final String cacheRegionName = cacheRegionPrefix + model.getCacheRegionName();
final AccessType accessType = AccessType.fromExternalName( model.getCacheConcurrencyStrategy() );
CollectionRegionAccessStrategy accessStrategy = null;
if ( accessType != null && settings.isSecondLevelCacheEnabled() ) {
LOG.tracev( "Building shared cache region for collection data [{0}]", model.getRole() );
CollectionRegion collectionRegion = regionFactory.buildCollectionRegion( cacheRegionName, properties, CacheDataDescriptionImpl
.decode( model ) );
accessStrategy = collectionRegion.buildAccessStrategy( accessType );
entityAccessStrategies.put( cacheRegionName, accessStrategy );
cacheAccess.addCacheRegion( cacheRegionName, collectionRegion );
}
CollectionPersister persister = persisterFactory.createCollectionPersister(
cfg,
model,
accessStrategy,
this
) ;
collectionPersisters.put( model.getRole(), persister );
tmpCollectionMetadata.put( model.getRole(), persister.getCollectionMetadata() );
Type indexType = persister.getIndexType();
if ( indexType != null && indexType.isAssociationType() && !indexType.isAnyType() ) {
String entityName = ( ( AssociationType ) indexType ).getAssociatedEntityName( this );
Set roles = tmpEntityToCollectionRoleMap.get( entityName );
if ( roles == null ) {
roles = new HashSet();
tmpEntityToCollectionRoleMap.put( entityName, roles );
}
roles.add( persister.getRole() );
}
Type elementType = persister.getElementType();
if ( elementType.isAssociationType() && !elementType.isAnyType() ) {
String entityName = ( ( AssociationType ) elementType ).getAssociatedEntityName( this );
Set roles = tmpEntityToCollectionRoleMap.get( entityName );
if ( roles == null ) {
roles = new HashSet();
tmpEntityToCollectionRoleMap.put( entityName, roles );
}
roles.add( persister.getRole() );
}
}
collectionMetadata = Collections.unmodifiableMap( tmpCollectionMetadata );
Iterator itr = tmpEntityToCollectionRoleMap.entrySet().iterator();
while ( itr.hasNext() ) {
final Map.Entry entry = ( Map.Entry ) itr.next();
entry.setValue( Collections.unmodifiableSet( ( Set ) entry.getValue() ) );
}
collectionRolesByEntityParticipant = Collections.unmodifiableMap( tmpEntityToCollectionRoleMap );
//Named Queries:
namedQueries = new HashMap<String, NamedQueryDefinition>( cfg.getNamedQueries() );
namedSqlQueries = new HashMap<String, NamedSQLQueryDefinition>( cfg.getNamedSQLQueries() );
sqlResultSetMappings = new HashMap<String, ResultSetMappingDefinition>( cfg.getSqlResultSetMappings() );
imports = new HashMap<String,String>( cfg.getImports() );
// after *all* persisters and named queries are registered
Iterator iter = entityPersisters.values().iterator();
while ( iter.hasNext() ) {
final EntityPersister persister = ( ( EntityPersister ) iter.next() );
persister.postInstantiate();
registerEntityNameResolvers( persister );
}
iter = collectionPersisters.values().iterator();
while ( iter.hasNext() ) {
final CollectionPersister persister = ( ( CollectionPersister ) iter.next() );
persister.postInstantiate();
}
//JNDI + Serialization:
//獲取當前設定的會話工廠名稱
name = settings.getSessionFactoryName();
//獲取uuid
try {
uuid = (String) UUID_GENERATOR.generate(null, null);
}
catch (Exception e) {
throw new AssertionFailure("Could not generate UUID");
}
//將當前的會話工廠加入會話工廠註冊
SessionFactoryRegistry.INSTANCE.addSessionFactory(
uuid,
name,
settings.isSessionFactoryNameAlsoJndiName(),
this,
serviceRegistry.getService( JndiService.class )
);
LOG.debug( "Instantiated session factory" );
settings.getMultiTableBulkIdStrategy().prepare(
jdbcServices,
buildLocalConnectionAccess(),
cfg.createMappings(),
cfg.buildMapping(),
properties
);
if ( settings.isAutoCreateSchema() ) {
new SchemaExport( serviceRegistry, cfg )
.setImportSqlCommandExtractor( serviceRegistry.getService( ImportSqlCommandExtractor.class ) )
.create( false, true );
}
if ( settings.isAutoUpdateSchema() ) {
new SchemaUpdate( serviceRegistry, cfg ).execute( false, true );
}
if ( settings.isAutoValidateSchema() ) {
new SchemaValidator( serviceRegistry, cfg ).validate();
}
if ( settings.isAutoDropSchema() ) {
schemaExport = new SchemaExport( serviceRegistry, cfg )
.setImportSqlCommandExtractor( serviceRegistry.getService( ImportSqlCommandExtractor.class ) );
}
currentSessionContext = buildCurrentSessionContext();
//checking for named queries
if ( settings.isNamedQueryStartupCheckingEnabled() ) {
final Map<String,HibernateException> errors = checkNamedQueries();
if ( ! errors.isEmpty() ) {
StringBuilder failingQueries = new StringBuilder( "Errors in named queries: " );
String sep = "";
for ( Map.Entry<String,HibernateException> entry : errors.entrySet() ) {
LOG.namedQueryError( entry.getKey(), entry.getValue() );
failingQueries.append( sep ).append( entry.getKey() );
sep = ", ";
}
throw new HibernateException( failingQueries.toString() );
}
}
// this needs to happen after persisters are all ready to go...
this.fetchProfiles = new HashMap();
itr = cfg.iterateFetchProfiles();
while ( itr.hasNext() ) {
final org.hibernate.mapping.FetchProfile mappingProfile =
( org.hibernate.mapping.FetchProfile ) itr.next();
final FetchProfile fetchProfile = new FetchProfile( mappingProfile.getName() );
for ( org.hibernate.mapping.FetchProfile.Fetch mappingFetch : mappingProfile.getFetches() ) {
// resolve the persister owning the fetch
final String entityName = getImportedClassName( mappingFetch.getEntity() );
final EntityPersister owner = entityName == null
? null
: entityPersisters.get( entityName );
if ( owner == null ) {
throw new HibernateException(
"Unable to resolve entity reference [" + mappingFetch.getEntity()
+ "] in fetch profile [" + fetchProfile.getName() + "]"
);
}
// validate the specified association fetch
Type associationType = owner.getPropertyType( mappingFetch.getAssociation() );
if ( associationType == null || !associationType.isAssociationType() ) {
throw new HibernateException( "Fetch profile [" + fetchProfile.getName() + "] specified an invalid association" );
}
// resolve the style
final Fetch.Style fetchStyle = Fetch.Style.parse( mappingFetch.getStyle() );
// then construct the fetch instance...
fetchProfile.addFetch( new Association( owner, mappingFetch.getAssociation() ), fetchStyle );
((Loadable) owner).registerAffectingFetchProfile( fetchProfile.getName() );
}
fetchProfiles.put( fetchProfile.getName(), fetchProfile );
}
this.customEntityDirtinessStrategy = determineCustomEntityDirtinessStrategy();
this.currentTenantIdentifierResolver = determineCurrentTenantIdentifierResolver( cfg.getCurrentTenantIdentifierResolver() );
this.transactionEnvironment = new TransactionEnvironmentImpl( this );
this.observer.sessionFactoryCreated( this );
}