hibernate加载映射文件浅析

先上图:

但我们调用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就知道如何与数据库交互了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值