学习Hibernate源码三_Hibernate中的配置文件解析 http://bsr1983.iteye.com/blog/1935617
本节要学习一下Hibernate的配置文件的具体加载、解析的过程,以及涉及到的相关代码,思路是建立一个简单的java项目,配置一个hbm文件,启动后,跟踪调试加载解析hbm的过程,学习相关的代码。
搭建项目后,将所需jar放入java项目的lib目录,在Hibernate的手册中说明此处也可以使用Maven来设置依赖jar,我这里还是使用比较原始的方式。直接建立一个lib目录放置所需要的jar包,然后设置classpath即可。
参考Hibernate手册中所说的,解释一下.hbm中几个具体配置项的相关注意事项。
property中包含name、type、column 这3个常用的属性。
如:
name属性用来设置访问对应的映射类中对应属性值的getter、setter方法,有时候可以只配置一个name属性,type和column可以省略。上述例子中的type并不是java的数据类型,也不是SQL数据库的类型,而是被称为hibernate映射类型,它是用来在Java数据类型和SQL数据类型之间做转换的。如果type属性未定义,则Hibernate会尝试确定正确的映射类型来进行转换。在某些情况下,这种使用java类文件反射的自动检测可能没有你所期望和需要的类型,例如上述的date属性,Hibernate不能确定这里的java.util.Date应该映射为SQL的哪种类型,是date、timestamp还是time?因此此处使用了一个timestamp来指定对应的是一个包含日期和时间信息的属性。
注意:Hibernate在处理映射文件时会根据反射来设置对应的映射类型,这将会耗费一定的时间和资源,如果你的应用对启动的性能非常在意,那么你就要考虑精确的定义要使用的类型。
此处我使用的是mysql数据库,并不是手册中的HSQLDB,我创建了一个UserInfo表,具体的配置文件如下:
- <?xml version='1.0' encoding='utf-8'?>
- <!DOCTYPE hibernate-configuration PUBLIC
- "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
- "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
- <hibernate-configuration>
- <session-factory>
- <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
- <property name="connection.url">jdbc:mysql://localhost:3306/hibernatecode</property>
- <property name="connection.username">root</property>
- <property name="connection.password">root</property>
- <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
- <mapping resource="com/ibsrapp/hibernatecode/domain/UserInfo.hbm.xml" />
- </session-factory>
- </hibernate-configuration>
接着是数据库表UserInfo的映射文件
- <?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC
- "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
- <hibernate-mapping package="com.ibsrapp.hibernatecode.domain">
- <class name="UserInfo" table="userinfo">
- <id name="id" type="java.lang.Integer">
- <column name="id" />
- <generator class="identity" />
- </id>
- <property name="name" type="java.lang.String" length="255" column="name"/>
- <property name="password" type="java.lang.String" length="255" column="password"/>
- <property name="birthday" type="java.util.Date" column="birthday" />
- </class>
最后是运行所需的类的主方法:
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- //创建配置对象
- Configuration configuration = new Configuration();
- //调用默认配置方法
- configuration.configure();
- //注册服务
- ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
- .applySettings(configuration.getProperties())
- .buildServiceRegistry();
- //根据所注册的服务创建sessionFactory
- SessionFactory sessionFactory = configuration
- .buildSessionFactory(serviceRegistry);
- UserInfo user = new UserInfo();
- user.setName("ibsrapp");
- user.setPassword("ibsrapp");
- user.setBirthday(new Date());
- //获取一个session
- Session session = sessionFactory.openSession();
- Transaction trans = session.beginTransaction();
- session.save(user);
- trans.commit();
- session.close();
- sessionFactory.close();
- System.out.print("save Success");
- }
接着按照main方法中的代码进行debug,看看将一个对象保存到数据库中所需的步骤和涉及的相关代码。
首先是
- //创建配置对象
- Configuration configuration = new Configuration();
- //调用默认配置方法
- configuration.configure();
查看Configuration的configure()方法,代码如下:
- public Configuration configure() throws HibernateException {
- configure( "/hibernate.cfg.xml" );
- return this;
- }
通过这个方法,我们就能明白为什么配置文件的名称默认是hibernate.cfg.xml,而且默认是放在src目录下了。
接着看一下configure( "/hibernate.cfg.xml" );所对应的方法
- public Configuration configure(String resource) throws HibernateException {
- LOG.configuringFromResource( resource );
- InputStream stream = getConfigurationInputStream( resource );
- return doConfigure( stream, resource );
- }
此处最终还是调用了doConfigure( stream, resource );代码如下
核心代码为:
- Document document = xmlHelper.createSAXReader( errorLogger, entityResolver )
- .read( new InputSource( stream ) );
- if ( errorLogger.hasErrors() ) {
- throw new MappingException( "invalid configuration", errorLogger.getErrors().get( 0 ) );
- }
- doConfigure( document );
即将所传递的流转换为一个org.dom4j.Document对象,然后调用
- protected Configuration doConfigure(Document doc) throws HibernateException {
- //获取根元素下(hibernate-configuration)的session-factory子节点
- Element sfNode = doc.getRootElement().element( "session-factory" );
- String name = sfNode.attributeValue( "name" );
- if ( name != null ) {
- properties.setProperty( Environment.SESSION_FACTORY_NAME, name );
- }
- addProperties( sfNode );
- //处理session-factory子节点
- parseSessionFactory( sfNode, name );
- Element secNode = doc.getRootElement().element( "security" );
- if ( secNode != null ) {
- parseSecurity( secNode );
- }
- LOG.configuredSessionFactory( name );
- LOG.debugf( "Properties: %s", properties );
- return this;
- }
其中用于处理session-factory子节点的方法如下:
可以看到mapping属性所指明的映射文件,以及class-cache之门的类粒度级别的缓存以及collection-cache指明的集合粒度级别的缓存都有对应的处理方法。
- 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 );
- }
- 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 );
- }
- }
- }
用于处理mapping映射文件的方法如下:
- 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.debugf( "Session-factory config [%s] named resource [%s] for mapping", name, resourceName );
- addResource( resourceName );
- }
- else if ( fileAttribute != null ) {
- final String fileName = fileAttribute.getValue();
- LOG.debugf( "Session-factory config [%s] named file [%s] for mapping", name, fileName );
- addFile( fileName );
- }
- else if ( jarAttribute != null ) {
- final String jarFileName = jarAttribute.getValue();
- LOG.debugf( "Session-factory config [%s] named jar file [%s] for mapping", name, jarFileName );
- addJar( new File( jarFileName ) );
- }
- else if ( packageAttribute != null ) {
- final String packageName = packageAttribute.getValue();
- LOG.debugf( "Session-factory config [%s] named package [%s] for mapping", name, packageName );
- addPackage( packageName );
- }
- else if ( classAttribute != null ) {
- final String className = classAttribute.getValue();
- LOG.debugf( "Session-factory config [%s] named class [%s] 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" );
- }
- }
可以看到这里的资源可以是以下5种类型中的一种resource、file、jar、package、class。对于每种资源这里都有不同的加载方式,
查看每一类资源对应的加载方法,最终会发现他们还是会以一种输入流的方式加载到一个XmlDocument对象中,然后调用下面的方法,将对应的类和数据表进行映射,并将其添加到metadataSourceQueue这个队列之中。
- 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 );
- }
- }
- }
- }
通过调用JPAMetadataProvider的getXMLContext()方法获取到一个XMLContext,调用XMLContext的public List<String> addDocument(Document doc)来将doc中所配置的相关class全部条件到一个List中,然后通过reflectionManager通过类名称将对应的配置加载为org.hibernate.annotations.common.reflection.XClass接口的一个实现。
然后将其加入到MetadataSourceQueue中。MetadataSourceQueue中包含一个声明为transient 的List<XClass>annotatedClasses,即annotatedClasses不需要进行序列化。
在Hibernate的手册中是通过
new Configuration().configure().buildSessionFactory();的方式来获取一个SessionFactory对象的,但是当前的代码中该方法以及被废弃,建议使用的方法是buildSessionFactory(ServiceRegistry)。
因此我们的主方法中使用的是推荐的方法。
Hibernate源码学习五_创建SessionFactoryhttp://bsr1983.iteye.com/blog/1941608
接学习四,下来就是调用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 );
- }