先上图:
但我们调用configuration的构造方法时实例化configuration时,会调用reset方法:
protected Configuration(SettingsFactory settingsFactory) {
this.settingsFactory = settingsFactory;
reset();
}
public Configuration() {
this( new SettingsFactory() );
}
reset方法实例化了metadataSourceQueue:
protected void reset() {
metadataSourceQueue = new MetadataSourceQueue();
......//省略下面的代码
}
这个对象将会用来保存映射信息。
hibernate获取实体关系映射信息有两种方式:
1.调用configuration的addResource(String resourceName)方法(也可以调用addClass()方法)。resourceName就是映射文件的路径。
2.调用configuration的config()方法。
跟踪代码发现,config()调用了doConfigure(Document doc)方法:
protected Configuration doConfigure(Document doc) throws HibernateException {
Element sfNode = doc.getRootElement().element( "session-factory" );
String name = sfNode.attributeValue( "name" );
if ( name != null ) {
properties.setProperty( Environment.SESSION_FACTORY_NAME, name );
}
addProperties( sfNode );
parseSessionFactory( sfNode, name );//解析hibernate配置文件的sessionFactory元素
Element secNode = doc.getRootElement().element( "security" );
if ( secNode != null ) {
parseSecurity( secNode );
}
log.info( "Configured SessionFactory: " + name );
log.debug( "properties: " + properties );
return this;
}
doConfigure(Document doc)调用了parseSessionFactory( sfNode, name ):
private void parseSessionFactory(Element sfNode, String name) {
Iterator elements = sfNode.elementIterator();
while ( elements.hasNext() ) {
Element subelement = (Element) elements.next();
String subelementName = subelement.getName();
if ( "mapping".equals( subelementName ) ) {
parseMappingElement( subelement, name );//解析mapping元素
}
else if ( "class-cache".equals( subelementName ) ) {
String className = subelement.attributeValue( "class" );
Attribute regionNode = subelement.attribute( "region" );
final String region = ( regionNode == null ) ? className : regionNode.getValue();
boolean includeLazy = !"non-lazy".equals( subelement.attributeValue( "include" ) );
setCacheConcurrencyStrategy( className, subelement.attributeValue( "usage" ), region, includeLazy );
}
else if ( "collection-cache".equals( subelementName ) ) {
String role = subelement.attributeValue( "collection" );
Attribute regionNode = subelement.attribute( "region" );
final String region = ( regionNode == null ) ? role : regionNode.getValue();
setCollectionCacheConcurrencyStrategy( role, subelement.attributeValue( "usage" ), region );
}
else if ( "listener".equals( subelementName ) ) {
parseListener( subelement );
}
else if ( "event".equals( subelementName ) ) {
parseEvent( subelement );
}
}
}
解析mapping元素时调用了parseMappingElement( subelement, name ):
private void parseMappingElement(Element mappingElement, String name) {
final Attribute resourceAttribute = mappingElement.attribute( "resource" );
final Attribute fileAttribute = mappingElement.attribute( "file" );
final Attribute jarAttribute = mappingElement.attribute( "jar" );
final Attribute packageAttribute = mappingElement.attribute( "package" );
final Attribute classAttribute = mappingElement.attribute( "class" );
if ( resourceAttribute != null ) {
final String resourceName = resourceAttribute.getValue();
log.debug( "session-factory config [{}] named resource [{}] for mapping", name, resourceName );
addResource( resourceName );//加载映射文件
}
else if ( fileAttribute != null ) {
final String fileName = fileAttribute.getValue();
log.debug( "session-factory config [{}] named file [{}] for mapping", name, fileName );
addFile( fileName );
}
else if ( jarAttribute != null ) {
final String jarFileName = jarAttribute.getValue();
log.debug( "session-factory config [{}] named jar file [{}] for mapping", name, jarFileName );
addJar( new File( jarFileName ) );
}
else if ( packageAttribute != null ) {
final String packageName = packageAttribute.getValue();
log.debug( "session-factory config [{}] named package [{}] for mapping", name, packageName );
addPackage( packageName );
}
else if ( classAttribute != null ) {
final String className = classAttribute.getValue();
log.debug( "session-factory config [{}] named class [{}] for mapping", name, className );
try {
addAnnotatedClass( ReflectHelper.classForName( className ) );
}
catch ( Exception e ) {
throw new MappingException(
"Unable to load class [ " + className + "] declared in Hibernate configuration <mapping/> entry",
e
);
}
}
else {
throw new MappingException( "<mapping> element in configuration specifies no known attributes" );
}
}
代码跟踪到这里,我们发现,如果mapping元素配置了resource属性,
使用config()方法获取映射信息,最终也还是调用了addResource(String resourceName)方法。
继续向下跟踪,addResource()调用了add(XmlDocument metadataXml)方法:
public void add(XmlDocument metadataXml) {
if ( inSecondPass || !isOrmXml( metadataXml ) ) {
metadataSourceQueue.add( metadataXml );
}
else {
final MetadataProvider metadataProvider = ( (MetadataProviderInjector) reflectionManager ).getMetadataProvider();
JPAMetadataProvider jpaMetadataProvider = ( JPAMetadataProvider ) metadataProvider;
List<String> classNames = jpaMetadataProvider.getXMLContext().addDocument( metadataXml.getDocumentTree() );
for ( String className : classNames ) {
try {
metadataSourceQueue.add( reflectionManager.classForName( className, this.getClass() ) );
}
catch ( ClassNotFoundException e ) {
throw new AnnotationException( "Unable to load class defined in XML: " + className, e );
}
}
}
}
最后将信息放入了metadataSourceQueue对象。
有了映射信息,我们就能实例化一个SessionFactory了。
调用configuration的buildSessionFactory()方法:
public SessionFactory buildSessionFactory() throws HibernateException {
log.debug( "Preparing to build session factory with filters : " + filterDefinitions );
secondPassCompile();
if ( ! metadataSourceQueue.isEmpty() ) {
log.warn( "mapping metadata cache was not completely processed" );
}
enableLegacyHibernateValidator();
enableBeanValidation();
enableHibernateSearch();
validate();
Environment.verifyProperties( properties );
Properties copy = new Properties();
copy.putAll( properties );
PropertiesHelper.resolvePlaceHolders( copy );
Settings settings = buildSettings( copy );
return new SessionFactoryImpl(
this,
mapping,
settings,
getInitializedEventListeners(),
sessionFactoryObserver
);
}
secondPassCompile()方法会从metadataSourceQueue对象中获取映射信息,最后映射信息会放到mapping对象中。
实例化SessionFactory的时候会把configuration对象和mapping对象传过去。通过configuration对象,SessionFactory可以获取基本的配置信息;通过mapping对象,SessionFactory可以获取实体关系映射配置信息。
public SessionFactoryImpl(
Configuration cfg,
Mapping mapping,
Settings settings,
EventListeners listeners,
SessionFactoryObserver observer) throws HibernateException {
log.info("building session factory");
this.statistics = new ConcurrentStatisticsImpl( this );
getStatistics().setStatisticsEnabled( settings.isStatisticsEnabled() );
log.debug( "Statistics initialized [enabled={}]}", settings.isStatisticsEnabled() );
this.properties = new Properties();
this.properties.putAll( cfg.getProperties() );
this.interceptor = cfg.getInterceptor();
this.settings = settings;
......//省略一些代码
///
// Prepare persisters and link them up with their cache
// region/access-strategy
final String cacheRegionPrefix = settings.getCacheRegionPrefix() == null ? "" : settings.getCacheRegionPrefix() + ".";
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, settings.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.parse( model.getCacheConcurrencyStrategy() );
if ( accessType != null ) {
log.trace( "Building cache for entity data [" + model.getEntityName() + "]" );
EntityRegion entityRegion = settings.getRegionFactory().buildEntityRegion( cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) );
accessStrategy = entityRegion.buildAccessStrategy( accessType );
entityAccessStrategies.put( cacheRegionName, accessStrategy );
allCacheRegions.put( cacheRegionName, entityRegion );
}
}
EntityPersister cp = PersisterFactory.createClassPersister( model, accessStrategy, this, mapping );
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();
Iterator collections = cfg.getCollectionMappings();
while ( collections.hasNext() ) {
Collection model = (Collection) collections.next();
final String cacheRegionName = cacheRegionPrefix + model.getCacheRegionName();
final AccessType accessType = AccessType.parse( model.getCacheConcurrencyStrategy() );
CollectionRegionAccessStrategy accessStrategy = null;
if ( accessType != null && settings.isSecondLevelCacheEnabled() ) {
log.trace( "Building cache for collection data [" + model.getRole() + "]" );
CollectionRegion collectionRegion = settings.getRegionFactory().buildCollectionRegion( cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) );
accessStrategy = collectionRegion.buildAccessStrategy( accessType );
entityAccessStrategies.put( cacheRegionName, accessStrategy );
allCacheRegions.put( cacheRegionName, collectionRegion );
}
CollectionPersister persister = PersisterFactory.createCollectionPersister( cfg, model, accessStrategy, this) ;
collectionPersisters.put( model.getRole(), persister.getCollectionMetadata() );
Type indexType = persister.getIndexType();
if ( indexType != null && indexType.isAssociationType() && !indexType.isAnyType() ) {
String entityName = ( ( AssociationType ) indexType ).getAssociatedEntityName( this );
Set roles = ( Set ) 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 = ( Set ) tmpEntityToCollectionRoleMap.get( entityName );
if ( roles == null ) {
roles = new HashSet();
tmpEntityToCollectionRoleMap.put( entityName, roles );
}
roles.add( persister.getRole() );
}
}
collectionMetadata = Collections.unmodifiableMap(collectionPersisters);
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 );
......//省略了一些代码
this.observer.sessionFactoryCreated( this );
}
构造方里解析了mapping对象,并且将解析后的映射信息放入了SessionFactory的成员变量中。于是,映射信息就从XML配置文件中传递给了SessionFactory。
SessionFactory有了映射信息后,通过它产生的session就知道如何与数据库交互了。