学习Hibernate源码——配置文件解析,SessionFactory创建

学习Hibernate源码三_Hibernate中的配置文件解析 http://bsr1983.iteye.com/blog/1935617


本节要学习一下Hibernate的配置文件的具体加载、解析的过程,以及涉及到的相关代码,思路是建立一个简单的java项目,配置一个hbm文件,启动后,跟踪调试加载解析hbm的过程,学习相关的代码。

      搭建项目后,将所需jar放入java项目的lib目录,在Hibernate的手册中说明此处也可以使用Maven来设置依赖jar,我这里还是使用比较原始的方式。直接建立一个lib目录放置所需要的jar包,然后设置classpath即可。

      参考Hibernate手册中所说的,解释一下.hbm中几个具体配置项的相关注意事项。

      (1)关于property元素

      property中包含name、type、column 这3个常用的属性。

   如:

 

Xml代码   收藏代码
  1.   
  2.   
   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代码   收藏代码
  1.   
  2.         "-//Hibernate/Hibernate Configuration DTD 3.0//EN"  
  3.         "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">  
  4.   
  5.       
  6.         org.hibernate.dialect.MySQLDialect  
  7.         jdbc:mysql://localhost:3306/hibernatecode  
  8.         root  
  9.         root  
  10.         com.mysql.jdbc.Driver  
  11.           
  12.       
  13.   

 

 

接着是数据库表UserInfo的映射文件

 

Xml代码   收藏代码
  1.   
  2.         "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  3.         "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">  
  4.   
  5.       
  6.            
  7.               
  8.               
  9.           
  10.           
  11.           
  12.           
  13.       

 

 

最后是运行所需的类的主方法:

 

Java代码   收藏代码
  1. public static void main(String[] args) {  
  2.       // TODO Auto-generated method stub  
  3.       //创建配置对象  
  4.       Configuration configuration = new Configuration();  
  5.       //调用默认配置方法  
  6.       configuration.configure();  
  7.       //注册服务  
  8.       ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()  
  9.             .applySettings(configuration.getProperties())  
  10.             .buildServiceRegistry();  
  11.       //根据所注册的服务创建sessionFactory  
  12.       SessionFactory sessionFactory = configuration  
  13.             .buildSessionFactory(serviceRegistry);  
  14.       UserInfo user = new UserInfo();  
  15.       user.setName("ibsrapp");  
  16.       user.setPassword("ibsrapp");  
  17.       user.setBirthday(new Date());  
  18.       //获取一个session  
  19.       Session session = sessionFactory.openSession();  
  20.       Transaction trans = session.beginTransaction();  
  21.       session.save(user);  
  22.       trans.commit();  
  23.       session.close();  
  24.       sessionFactory.close();  
  25.       System.out.print("save Success");  
  26.   }  

 

 

接着按照main方法中的代码进行debug,看看将一个对象保存到数据库中所需的步骤和涉及的相关代码。

首先是

 

Java代码   收藏代码
  1. //创建配置对象  
  2. Configuration configuration = new Configuration();  
  3. //调用默认配置方法  
  4. configuration.configure();  

 

 

查看Configuration的configure()方法,代码如下:

 

Java代码   收藏代码
  1. public Configuration configure() throws HibernateException {  
  2.       configure( "/hibernate.cfg.xml" );  
  3.       return this;  
  4.   }  

 

 

通过这个方法,我们就能明白为什么配置文件的名称默认是hibernate.cfg.xml而且默认是放在src目录下了。

接着看一下configure( "/hibernate.cfg.xml" );所对应的方法

 

Java代码   收藏代码
  1. public Configuration configure(String resource) throws HibernateException {  
  2.       LOG.configuringFromResource( resource );  
  3.       InputStream stream = getConfigurationInputStream( resource );  
  4.       return doConfigure( stream, resource );  
  5.   }  

 

 

此处最终还是调用了doConfigure( stream, resource );代码如下

核心代码为:

 

Java代码   收藏代码
  1. Document document = xmlHelper.createSAXReader( errorLogger,  entityResolver )  
  2.                 .read( new InputSource( stream ) );  
  3.          if ( errorLogger.hasErrors() ) {  
  4.             throw new MappingException( "invalid configuration", errorLogger.getErrors().get( 0 ) );  
  5.          }  
  6.          doConfigure( document );  

 

 

即将所传递的流转换为一个org.dom4j.Document对象,然后调用

 

Java代码   收藏代码
  1. protected Configuration doConfigure(Document doc) throws HibernateException {  
  2. //获取根元素下(hibernate-configuration)的session-factory子节点        
  3.       Element sfNode = doc.getRootElement().element( "session-factory" );  
  4.       String name = sfNode.attributeValue( "name" );  
  5.       if ( name != null ) {  
  6.          properties.setProperty( Environment.SESSION_FACTORY_NAME, name );  
  7.       }  
  8.       addProperties( sfNode );  
  9.       //处理session-factory子节点  
  10.       parseSessionFactory( sfNode, name );  
  11.    
  12.       Element secNode = doc.getRootElement().element( "security" );  
  13.       if ( secNode != null ) {  
  14.          parseSecurity( secNode );  
  15.       }  
  16.    
  17.       LOG.configuredSessionFactory( name );  
  18.       LOG.debugf( "Properties: %s", properties );  
  19.    
  20.       return this;  
  21.    }  

 

 

其中用于处理session-factory子节点的方法如下:

可以看到mapping属性所指明的映射文件,以及class-cache之门的类粒度级别的缓存以及collection-cache指明的集合粒度级别的缓存都有对应的处理方法。

 

Java代码   收藏代码
  1. private void parseSessionFactory(Element sfNode, String name) {  
  2.       Iterator elements = sfNode.elementIterator();  
  3.       while ( elements.hasNext() ) {  
  4.          Element subelement = (Element) elements.next();  
  5.          String subelementName = subelement.getName();  
  6.          if ( "mapping".equals( subelementName ) ) {  
  7.             parseMappingElement( subelement, name );  
  8.          }  
  9.          else if ( "class-cache".equals( subelementName ) ) {  
  10.             String className = subelement.attributeValue( "class" );  
  11.             Attribute regionNode = subelement.attribute( "region" );  
  12.             final String region = ( regionNode == null ) ? className : regionNode.getValue();  
  13.             boolean includeLazy = !"non-lazy".equals( subelement.attributeValue( "include" ) );  
  14.             setCacheConcurrencyStrategy( className, subelement.attributeValue( "usage" ), region, includeLazy );  
  15.          }  
  16.          else if ( "collection-cache".equals( subelementName ) ) {  
  17.             String role = subelement.attributeValue( "collection" );  
  18.             Attribute regionNode = subelement.attribute( "region" );  
  19.             final String region = ( regionNode == null ) ? role : regionNode.getValue();  
  20.             setCollectionCacheConcurrencyStrategy( role, subelement.attributeValue( "usage" ), region );  
  21.          }  
  22.       }  
  23.   }  

 

 

用于处理mapping映射文件的方法如下:

 

Java代码   收藏代码
  1. private void parseMappingElement(Element mappingElement, String name) {  
  2.       final Attribute resourceAttribute = mappingElement.attribute( "resource" );  
  3.       final Attribute fileAttribute = mappingElement.attribute( "file" );  
  4.       final Attribute jarAttribute = mappingElement.attribute( "jar" );  
  5.       final Attribute packageAttribute = mappingElement.attribute( "package" );  
  6.       final Attribute classAttribute = mappingElement.attribute( "class" );  
  7.    
  8.       if ( resourceAttribute != null ) {  
  9.          final String resourceName = resourceAttribute.getValue();  
  10.          LOG.debugf( "Session-factory config [%s] named resource [%s] for mapping", name, resourceName );  
  11.          addResource( resourceName );  
  12.       }  
  13.       else if ( fileAttribute != null ) {  
  14.          final String fileName = fileAttribute.getValue();  
  15.          LOG.debugf( "Session-factory config [%s] named file [%s] for mapping", name, fileName );  
  16.          addFile( fileName );  
  17.       }  
  18.       else if ( jarAttribute != null ) {  
  19.          final String jarFileName = jarAttribute.getValue();  
  20.          LOG.debugf( "Session-factory config [%s] named jar file [%s] for mapping", name, jarFileName );  
  21.          addJar( new File( jarFileName ) );  
  22.       }  
  23.       else if ( packageAttribute != null ) {  
  24.          final String packageName = packageAttribute.getValue();  
  25.         LOG.debugf( "Session-factory config [%s] named package [%s] for mapping", name, packageName );  
  26.          addPackage( packageName );  
  27.       }  
  28.       else if ( classAttribute != null ) {  
  29.          final String className = classAttribute.getValue();  
  30.          LOG.debugf( "Session-factory config [%s] named class [%s] for mapping", name, className );  
  31.          try {  
  32.             addAnnotatedClass( ReflectHelper.classForName( className ) );  
  33.          }  
  34.          catch ( Exception e ) {  
  35.             throw new MappingException(  
  36.                    "Unable to load class [ " + className + "] declared in Hibernate configuration  entry",  
  37.                    e  
  38.             );  
  39.          }  
  40.       }  
  41.       else {  
  42.          throw new MappingException( " element in configuration specifies no known attributes" );  
  43.       }  
  44.   }  

 

 

可以看到这里的资源可以是以下5种类型中的一种resourcefilejarpackageclass对于每种资源这里都有不同的加载方式,

查看每一类资源对应的加载方法,最终会发现他们还是会以一种输入流的方式加载到一个XmlDocument对象中,然后调用下面的方法,将对应的类和数据表进行映射,并将其添加到metadataSourceQueue这个队列之中。

 

Java代码   收藏代码
  1. public void add(XmlDocument metadataXml) {  
  2.       if ( inSecondPass || !isOrmXml( metadataXml ) ) {  
  3.          metadataSourceQueue.add( metadataXml );  
  4.       }  
  5.       else {  
  6.          final MetadataProvider metadataProvider = ( (MetadataProviderInjector) reflectionManager ).getMetadataProvider();  
  7.          JPAMetadataProvider jpaMetadataProvider = ( JPAMetadataProvider ) metadataProvider;  
  8.          List classNames = jpaMetadataProvider.getXMLContext().addDocument( metadataXml.getDocumentTree() );  
  9.          for ( String className : classNames ) {  
  10.             try {  
  11.                 metadataSourceQueue.add( reflectionManager.classForName( className, this.getClass() ) );  
  12.             }  
  13.             catch ( ClassNotFoundException e ) {  
  14.                 throw new AnnotationException( "Unable to load class defined in XML: " + className, e );  
  15.             }  
  16.          }  
  17.       }  
  18.   }  

 

通过调用JPAMetadataProvider的getXMLContext()方法获取到一个XMLContext,调用XMLContext的public List addDocument(Document doc)来将doc中所配置的相关class全部条件到一个List中,然后通过reflectionManager通过类名称将对应的配置加载为org.hibernate.annotations.common.reflection.XClass接口的一个实现。

然后将其加入到MetadataSourceQueue中。MetadataSourceQueue中包含一个声明为transient 的ListannotatedClasses,即annotatedClasses不需要进行序列化。

  在Hibernate的手册中是通过

new Configuration().configure().buildSessionFactory();的方式来获取一个SessionFactory对象的,但是当前的代码中该方法以及被废弃,建议使用的方法是buildSessionFactory(ServiceRegistry)。

因此我们的主方法中使用的是推荐的方法。


Hibernate源码学习五_创建SessionFactoryhttp://bsr1983.iteye.com/blog/1941608

接学习四,下来就是调用configuration的buildSessionFactory方法来创建一个sessionFactory了,具体代码如下:

Java代码   收藏代码
  1. public SessionFactory buildSessionFactory(ServiceRegistry serviceRegistry) throws HibernateException {  
  2.         LOG.debugf( "Preparing to build session factory with filters : %s", filterDefinitions );  
  3.         //注册类型,包含数据库方言  
  4.         buildTypeRegistrations( serviceRegistry );  
  5.         //二次传递编译,包含注解处理  
  6.         secondPassCompile();  
  7.         if ( !metadataSourceQueue.isEmpty() ) {  
  8.             LOG.incompleteMappingMetadataCacheProcessing();  
  9.         }  
  10.         //校验所配置的映射类与hbm配置文件中的属性是否一致  
  11.         validate();  
  12.        //校验全局配置属性  
  13.         Environment.verifyProperties( properties );  
  14.         Properties copy = new Properties();  
  15.         copy.putAll( properties );  
  16.         //拷贝一份配置,处理占位符  
  17.         ConfigurationHelper.resolvePlaceHolders( copy );  
  18.         //通过配置的属性和注册的服务创建一个设置  
  19.         Settings settings = buildSettings( copy, serviceRegistry );  
  20.         //通过注册的服务,映射文件,设置,以及一个session工厂的观察者//(用于监视会话工厂状态)来创建一个会话工厂的实现  
  21.         return new SessionFactoryImpl(  
  22.                 this,  
  23.                 mapping,  
  24.                 serviceRegistry,  
  25.                 settings,  
  26.                 sessionFactoryObserver  
  27.             );  
  28.     }  

 下面看一下上述的secondPassCompile()二次传递编译方法secondPassCompile()的具体代码:

Java代码   收藏代码
  1. protected void secondPassCompile () throws MappingException {  
  2.         LOG.trace( "Starting secondPassCompile() processing" );  
  3.           
  4.         // TEMPORARY  
  5.         // Ensure the correct ClassLoader is used in commons-annotations.  
  6. //获取当前线程中所使用的classLoader,便于处理结束后,将该classloader在设置为当//前线程所使用的类加载器,仅用于保留对象  
  7.         ClassLoader tccl = Thread.currentThread().getContextClassLoader();  
  8.     //获取ClassLoaderHelper中的上下文类加载器并设置到当前线程,确保所使用的类//加载器,查看实际代码,发现其实返回的还是当前线程所使用的上下文加载器,但//ClassLoaderHelper注释中说明该属性可以通过客户自定义注入来进行替换,而且在//Hibernate5中将被替换为其他方式,具体参见ClassLoaderHelper源码   Thread.currentThread().setContextClassLoader( ClassLoaderHelper.getContextClassLoader() );  
  9.   
  10.         //process default values first,第一次处理的时候需要设置一下默认值  
  11.         {  
  12.             if ( !isDefaultProcessed ) {  
  13.                 //use global delimiters if orm.xml declare it  
  14.                 Map defaults = reflectionManager.getDefaults();  
  15.                 final Object isDelimited = defaults.get( "delimited-identifier" );  
  16.                 if ( isDelimited != null && isDelimited == Boolean.TRUE ) {  
  17.                     getProperties().put( Environment.GLOBALLY_QUOTED_IDENTIFIERS, "true" );  
  18.                 }  
  19.                 // Set default schema name if orm.xml declares it.  
  20.                 final String schema = (String) defaults.get( "schema" );  
  21.                 if ( StringHelper.isNotEmpty( schema ) ) {  
  22.                     getProperties().put( Environment.DEFAULT_SCHEMA, schema );  
  23.                 }  
  24.                 // Set default catalog name if orm.xml declares it.  
  25.                 final String catalog = (String) defaults.get( "catalog" );  
  26.                 if ( StringHelper.isNotEmpty( catalog ) ) {  
  27.                     getProperties().put( Environment.DEFAULT_CATALOG, catalog );  
  28.                 }  
  29.                 //注解绑定  
  30.                 AnnotationBinder.bindDefaults( createMappings() );  
  31.                 isDefaultProcessed = true;  
  32.             }  
  33.         }  
  34.   
  35.         // process metadata queue  
  36.         {  
  37.             metadataSourceQueue.syncAnnotatedClasses();  
  38.             metadataSourceQueue.processMetadata( determineMetadataSourcePrecedence() );  
  39.         }  
  40.   
  41.   
  42.   
  43.         try {  
  44.             inSecondPass = true;  
  45.             processSecondPassesOfType( PkDrivenByDefaultMapsIdSecondPass.class );  
  46.             processSecondPassesOfType( SetSimpleValueTypeSecondPass.class );  
  47.             processSecondPassesOfType( CopyIdentifierComponentSecondPass.class );  
  48.             processFkSecondPassInOrder();  
  49.             processSecondPassesOfType( CreateKeySecondPass.class );  
  50.             processSecondPassesOfType( SecondaryTableSecondPass.class );  
  51.   
  52.             originalSecondPassCompile();  
  53.   
  54.             inSecondPass = false;  
  55.         }  
  56.         catch ( RecoverableException e ) {  
  57.             //the exception was not recoverable after all  
  58.             throw ( RuntimeException ) e.getCause();  
  59.         }  
  60.   
  61.         // process cache queue,缓存队列处理  
  62.         {  
  63.             for ( CacheHolder holder : caches ) {  
  64.                 if ( holder.isClass ) {  
  65.                     applyCacheConcurrencyStrategy( holder );  
  66.                 }  
  67.                 else {  
  68.                     applyCollectionCacheConcurrencyStrategy( holder );  
  69.                 }  
  70.             }  
  71.             caches.clear();  
  72.         }  
  73.         //唯一约束处理  
  74.         for ( Map.Entry> tableListEntry : uniqueConstraintHoldersByTable.entrySet() ) {  
  75.             final Table table = tableListEntry.getKey();  
  76.             final List uniqueConstraints = tableListEntry.getValue();  
  77.             for ( UniqueConstraintHolder holder : uniqueConstraints ) {  
  78.                 buildUniqueKeyFromColumnNames( table, holder.getName(), holder.getColumns() );  
  79.             }  
  80.         }  
  81.         //恢复当前线程的上下文类加载器为初始上下文类加载器  
  82.         Thread.currentThread().setContextClassLoader( tccl );  
  83.     }  

 创建sessionFactory所使用的构造函数代码:

Java代码   收藏代码
  1. public SessionFactoryImpl(  
  2.             final Configuration cfg,  
  3.             Mapping mapping,  
  4.             ServiceRegistry serviceRegistry,  
  5.             Settings settings,  
  6.             SessionFactoryObserver observer) throws HibernateException {  
  7.             LOG.debug( "Building session factory" );  
  8. //session工厂的设置项  
  9.         sessionFactoryOptions = new SessionFactoryOptions() {  
  10.             private EntityNotFoundDelegate entityNotFoundDelegate;  
  11.   
  12.             @Override  
  13.             public Interceptor getInterceptor() {  
  14.                 return cfg.getInterceptor();  
  15.             }  
  16.   
  17.             @Override  
  18.             public EntityNotFoundDelegate getEntityNotFoundDelegate() {  
  19.                 if ( entityNotFoundDelegate == null ) {  
  20.                     if ( cfg.getEntityNotFoundDelegate() != null ) {  
  21.                         entityNotFoundDelegate = cfg.getEntityNotFoundDelegate();  
  22.                     }  
  23.                     else {  
  24.                         entityNotFoundDelegate = new EntityNotFoundDelegate() {  
  25.                             public void handleEntityNotFound(String entityName, Serializable id) {  
  26.                                 throw new ObjectNotFoundException( id, entityName );  
  27.                             }  
  28.                         };  
  29.                     }  
  30.                 }  
  31.                 return entityNotFoundDelegate;  
  32.             }  
  33.         };  
  34.   
  35.         this.settings = settings;  
  36.   
  37.         this.properties = new Properties();  
  38.         this.properties.putAll( cfg.getProperties() );  
  39.   
  40.         this.serviceRegistry = serviceRegistry.getService( SessionFactoryServiceRegistryFactory.class ).buildServiceRegistry(  
  41.                 this,  
  42.                 cfg  
  43.         );  
  44.         //jdbc服务  
  45. this.jdbcServices = this.serviceRegistry.getService( JdbcServices.class );  
  46. //方言  
  47.         this.dialect = this.jdbcServices.getDialect();  
  48. //缓存访问服务  
  49.         this.cacheAccess = this.serviceRegistry.getService( CacheImplementor.class );  
  50.         final RegionFactory regionFactory = cacheAccess.getRegionFactory();  
  51. //sql函数注册,将配置中的自定义方法及制定数据库方言中的方法注册到一个//以方法名称为key,对应的方言所对英的SQLFunction接口实现类的 Map中,  
  52.         this.sqlFunctionRegistry = new SQLFunctionRegistry( getDialect(), cfg.getSqlFunctions() );  
  53. //如果指定的观察者不为空,将其添加到当前的观察者链中//SessionFactoryObserverChain  
  54.         if ( observer != null ) {  
  55.             this.observer.addObserver( observer );  
  56.         }  
  57.   
  58.         this.typeResolver = cfg.getTypeResolver().scope( this );  
  59.         this.typeHelper = new TypeLocatorImpl( typeResolver );  
  60. //过滤器  
  61.         this.filters = new HashMap();  
  62.         this.filters.putAll( cfg.getFilterDefinitions() );  
  63.   
  64.         LOG.debugf( "Session factory constructed with filter configurations : %s", filters );  
  65.         LOG.debugf( "Instantiating session factory with properties: %s", properties );  
  66.   
  67. //查询计划缓存  
  68.         this.queryPlanCache = new QueryPlanCache( this );  
  69.   
  70.         // todo : everything above here consider implementing as standard SF service.  specifically: stats, caches, types, function-reg  
  71. //内部类,用于定义一个拦截器的SessionFactory观察者  
  72. //拦截器接口可以用于在对持久类进行加载、编辑、更新等操作前进行处理,可//以用于记录操作信息  
  73.         class IntegratorObserver implements SessionFactoryObserver {  
  74.             private ArrayList integrators = new ArrayList();  
  75.   
  76.             @Override  
  77.             public void sessionFactoryCreated(SessionFactory factory) {  
  78.             }  
  79.   
  80.             @Override  
  81. //sessionFactory关闭时,调用每个拦截器的回调方法disintegrate  
  82.             public void sessionFactoryClosed(SessionFactory factory) {  
  83.                 for ( Integrator integrator : integrators ) {  
  84.                     integrator.disintegrate( SessionFactoryImpl.this, SessionFactoryImpl.this.serviceRegistry );  
  85.                 }  
  86.             }  
  87.         }  
  88. //拦截器观察着  
  89.         final IntegratorObserver integratorObserver = new IntegratorObserver();  
  90. //将拦截器的观察者加入当前的观察者链中  
  91.         this.observer.addObserver( integratorObserver );  
  92. //获取拦截器对应的服务类,设置拦截  
  93.         for ( Integrator integrator : serviceRegistry.getService( IntegratorService.class ).getIntegrators() ) {  
  94.             integrator.integrate( cfg, this, this.serviceRegistry );  
  95.             integratorObserver.integrators.add( integrator );  
  96.         }  
  97.   
  98.         //Generators:  
  99. //标示符生成器  
  100.         identifierGenerators = new HashMap();  
  101. //获取当前配置中的所有映射类  
  102.         Iterator classes = cfg.getClassMappings();  
  103.         while ( classes.hasNext() ) {  
  104.             PersistentClass model = (PersistentClass) classes.next();  
  105. //如果当前映射类的定义不是继承的,则根据其定义进行设置  
  106.             if ( !model.isInherited() ) {  
  107.                 IdentifierGenerator generator = model.getIdentifier().createIdentifierGenerator(  
  108.                         cfg.getIdentifierGeneratorFactory(),  
  109.                         getDialect(),  
  110.                         settings.getDefaultCatalogName(),  
  111.                         settings.getDefaultSchemaName(),  
  112.                         (RootClass) model  
  113.                 );  
  114.                 //设定持久类的标示符生成器  
  115.                 identifierGenerators.put( model.getEntityName(), generator );  
  116.             }  
  117.         }  
  118.   
  119.   
  120.         ///////////////////////////////////////////////////////////////////////  
  121.         // Prepare persisters and link them up with their cache  
  122.         // region/access-strategy  
  123. //获取设置中的缓存范围  
  124.         final String cacheRegionPrefix = settings.getCacheRegionPrefix() == null ? "" : settings.getCacheRegionPrefix() + ".";  
  125. //持久化工厂服务  
  126.         final PersisterFactory persisterFactory = serviceRegistry.getService( PersisterFactory.class );  
  127. //持久类  
  128.         entityPersisters = new HashMap();  
  129.         Map entityAccessStrategies = new HashMap();  
  130.         Map classMeta = new HashMap();  
  131. //获取所有映射类  
  132.         classes = cfg.getClassMappings();  
  133.         while ( classes.hasNext() ) {  
  134.             final PersistentClass model = (PersistentClass) classes.next();  
  135.             model.prepareTemporaryTables( mapping, getDialect() );  
  136.             final String cacheRegionName = cacheRegionPrefix + model.getRootClass().getCacheRegionName();  
  137.             // cache region is defined by the root-class in the hierarchy...  
  138.             EntityRegionAccessStrategy accessStrategy = ( EntityRegionAccessStrategy ) entityAccessStrategies.get( cacheRegionName );  
  139.             if ( accessStrategy == null && settings.isSecondLevelCacheEnabled() ) {  
  140.                 final AccessType accessType = AccessType.fromExternalName( model.getCacheConcurrencyStrategy() );  
  141.                 if ( accessType != null ) {  
  142.                     LOG.tracef( "Building shared cache region for entity data [%s]", model.getEntityName() );  
  143.                     EntityRegion entityRegion = regionFactory.buildEntityRegion( cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) );  
  144.                     accessStrategy = entityRegion.buildAccessStrategy( accessType );  
  145.                     entityAccessStrategies.put( cacheRegionName, accessStrategy );  
  146.                     cacheAccess.addCacheRegion( cacheRegionName, entityRegion );  
  147.                 }  
  148.             }  
  149.               
  150.             NaturalIdRegionAccessStrategy naturalIdAccessStrategy = null;  
  151.             if ( model.hasNaturalId() && model.getNaturalIdCacheRegionName() != null ) {  
  152.                 final String naturalIdCacheRegionName = cacheRegionPrefix + model.getNaturalIdCacheRegionName();  
  153.                 naturalIdAccessStrategy = ( NaturalIdRegionAccessStrategy ) entityAccessStrategies.get( naturalIdCacheRegionName );  
  154.                   
  155.                 if ( naturalIdAccessStrategy == null && settings.isSecondLevelCacheEnabled() ) {  
  156.                     final CacheDataDescriptionImpl cacheDataDescription = CacheDataDescriptionImpl.decode( model );  
  157.                       
  158.                     NaturalIdRegion naturalIdRegion = null;  
  159.                     try {  
  160.                         naturalIdRegion = regionFactory.buildNaturalIdRegion( naturalIdCacheRegionName, properties,  
  161.                                 cacheDataDescription );  
  162.                     }  
  163.                     catch ( UnsupportedOperationException e ) {  
  164.                         LOG.warnf(  
  165.                                 "Shared cache region factory [%s] does not support natural id caching; " +  
  166.                                         "shared NaturalId caching will be disabled for not be enabled for %s",  
  167.                                 regionFactory.getClass().getName(),  
  168.                                 model.getEntityName()  
  169.                         );  
  170.                     }  
  171.                       
  172.                     if (naturalIdRegion != null) {  
  173.                         naturalIdAccessStrategy = naturalIdRegion.buildAccessStrategy( regionFactory.getDefaultAccessType() );  
  174.                         entityAccessStrategies.put( naturalIdCacheRegionName, naturalIdAccessStrategy );  
  175.                         cacheAccess.addCacheRegion(  naturalIdCacheRegionName, naturalIdRegion );  
  176.                     }  
  177.                 }  
  178.             }  
  179.             //根据上述配置生成一个实体映射  
  180.             EntityPersister cp = persisterFactory.createEntityPersister(  
  181.                     model,  
  182.                     accessStrategy,  
  183.                     naturalIdAccessStrategy,  
  184.                     this,  
  185.                     mapping  
  186.             );  
  187.     //以实体映射的名称为key,将对应的持久类加入entityPersisters  
  188.             entityPersisters.put( model.getEntityName(), cp );  
  189.             classMeta.put( model.getEntityName(), cp.getClassMetadata() );  
  190.         }  
  191.         this.classMetadata = Collections.unmodifiableMap(classMeta);  
  192.   
  193.         Map> tmpEntityToCollectionRoleMap = new HashMap>();  
  194.         collectionPersisters = new HashMap();  
  195.         Map tmpCollectionMetadata = new HashMap();  
  196.         Iterator collections = cfg.getCollectionMappings();  
  197.         while ( collections.hasNext() ) {  
  198.             Collection model = (Collection) collections.next();  
  199.             final String cacheRegionName = cacheRegionPrefix + model.getCacheRegionName();  
  200.             final AccessType accessType = AccessType.fromExternalName( model.getCacheConcurrencyStrategy() );  
  201.             CollectionRegionAccessStrategy accessStrategy = null;  
  202.             if ( accessType != null && settings.isSecondLevelCacheEnabled() ) {  
  203.                 LOG.tracev( "Building shared cache region for collection data [{0}]", model.getRole() );  
  204.                 CollectionRegion collectionRegion = regionFactory.buildCollectionRegion( cacheRegionName, properties, CacheDataDescriptionImpl  
  205.                         .decode( model ) );  
  206.                 accessStrategy = collectionRegion.buildAccessStrategy( accessType );  
  207.                 entityAccessStrategies.put( cacheRegionName, accessStrategy );  
  208.                 cacheAccess.addCacheRegion( cacheRegionName, collectionRegion );  
  209.             }  
  210.             CollectionPersister persister = persisterFactory.createCollectionPersister(  
  211.                     cfg,  
  212.                     model,  
  213.                     accessStrategy,  
  214.                     this  
  215.             ) ;  
  216.             collectionPersisters.put( model.getRole(), persister );  
  217.             tmpCollectionMetadata.put( model.getRole(), persister.getCollectionMetadata() );  
  218.             Type indexType = persister.getIndexType();  
  219.             if ( indexType != null && indexType.isAssociationType() && !indexType.isAnyType() ) {  
  220.                 String entityName = ( ( AssociationType ) indexType ).getAssociatedEntityName( this );  
  221.                 Set roles = tmpEntityToCollectionRoleMap.get( entityName );  
  222.                 if ( roles == null ) {  
  223.                     roles = new HashSet();  
  224.                     tmpEntityToCollectionRoleMap.put( entityName, roles );  
  225.                 }  
  226.                 roles.add( persister.getRole() );  
  227.             }  
  228.             Type elementType = persister.getElementType();  
  229.             if ( elementType.isAssociationType() && !elementType.isAnyType() ) {  
  230.                 String entityName = ( ( AssociationType ) elementType ).getAssociatedEntityName( this );  
  231.                 Set roles = tmpEntityToCollectionRoleMap.get( entityName );  
  232.                 if ( roles == null ) {  
  233.                     roles = new HashSet();  
  234.                     tmpEntityToCollectionRoleMap.put( entityName, roles );  
  235.                 }  
  236.                 roles.add( persister.getRole() );  
  237.             }  
  238.         }  
  239.         collectionMetadata = Collections.unmodifiableMap( tmpCollectionMetadata );  
  240.         Iterator itr = tmpEntityToCollectionRoleMap.entrySet().iterator();  
  241.         while ( itr.hasNext() ) {  
  242.             final Map.Entry entry = ( Map.Entry ) itr.next();  
  243.             entry.setValue( Collections.unmodifiableSet( ( Set ) entry.getValue() ) );  
  244.         }  
  245.         collectionRolesByEntityParticipant = Collections.unmodifiableMap( tmpEntityToCollectionRoleMap );  
  246.   
  247.         //Named Queries:  
  248.         namedQueries = new HashMap( cfg.getNamedQueries() );  
  249.         namedSqlQueries = new HashMap( cfg.getNamedSQLQueries() );  
  250.         sqlResultSetMappings = new HashMap( cfg.getSqlResultSetMappings() );  
  251.         imports = new HashMap( cfg.getImports() );  
  252.   
  253.         // after *all* persisters and named queries are registered  
  254.         Iterator iter = entityPersisters.values().iterator();  
  255.         while ( iter.hasNext() ) {  
  256.             final EntityPersister persister = ( ( EntityPersister ) iter.next() );  
  257.             persister.postInstantiate();  
  258.             registerEntityNameResolvers( persister );  
  259.   
  260.         }  
  261.         iter = collectionPersisters.values().iterator();  
  262.         while ( iter.hasNext() ) {  
  263.             final CollectionPersister persister = ( ( CollectionPersister ) iter.next() );  
  264.             persister.postInstantiate();  
  265.         }  
  266.   
  267.         //JNDI + Serialization:  
  268. //获取当前设置的会话工厂名称  
  269.         name = settings.getSessionFactoryName();  
  270. //获取uuid  
  271.         try {  
  272.             uuid = (String) UUID_GENERATOR.generate(null, null);  
  273.         }  
  274.         catch (Exception e) {  
  275.             throw new AssertionFailure("Could not generate UUID");  
  276.         }  
  277.     //将当前的会话工厂加入会话工厂注册  
  278.         SessionFactoryRegistry.INSTANCE.addSessionFactory(  
  279.                 uuid,  
  280.                 name,  
  281.                 settings.isSessionFactoryNameAlsoJndiName(),  
  282.                 this,  
  283.                 serviceRegistry.getService( JndiService.class )  
  284.         );  
  285.   
  286.         LOG.debug( "Instantiated session factory" );  
  287.   
  288.         settings.getMultiTableBulkIdStrategy().prepare(  
  289.                 jdbcServices,  
  290.                 buildLocalConnectionAccess(),  
  291.                 cfg.createMappings(),  
  292.                 cfg.buildMapping(),  
  293.                 properties  
  294.         );  
  295.   
  296.   
  297.         if ( settings.isAutoCreateSchema() ) {  
  298.             new SchemaExport( serviceRegistry, cfg )  
  299.                     .setImportSqlCommandExtractor( serviceRegistry.getService( ImportSqlCommandExtractor.class ) )  
  300.                     .create( false, true );  
  301.         }  
  302.         if ( settings.isAutoUpdateSchema() ) {  
  303.             new SchemaUpdate( serviceRegistry, cfg ).execute( false, true );  
  304.         }  
  305.         if ( settings.isAutoValidateSchema() ) {  
  306.             new SchemaValidator( serviceRegistry, cfg ).validate();  
  307.         }  
  308.         if ( settings.isAutoDropSchema() ) {  
  309.             schemaExport = new SchemaExport( serviceRegistry, cfg )  
  310.                     .setImportSqlCommandExtractor( serviceRegistry.getService( ImportSqlCommandExtractor.class ) );  
  311.         }  
  312.   
  313.         currentSessionContext = buildCurrentSessionContext();  
  314.   
  315.         //checking for named queries  
  316.         if ( settings.isNamedQueryStartupCheckingEnabled() ) {  
  317.             final Map errors = checkNamedQueries();  
  318.             if ( ! errors.isEmpty() ) {  
  319.                 StringBuilder failingQueries = new StringBuilder( "Errors in named queries: " );  
  320.                 String sep = "";  
  321.                 for ( Map.Entry entry : errors.entrySet() ) {  
  322.                     LOG.namedQueryError( entry.getKey(), entry.getValue() );  
  323.                     failingQueries.append( sep ).append( entry.getKey() );  
  324.                     sep = ", ";  
  325.                 }  
  326.                 throw new HibernateException( failingQueries.toString() );  
  327.             }  
  328.         }  
  329.   
  330.         // this needs to happen after persisters are all ready to go...  
  331.         this.fetchProfiles = new HashMap();  
  332.         itr = cfg.iterateFetchProfiles();  
  333.         while ( itr.hasNext() ) {  
  334.             final org.hibernate.mapping.FetchProfile mappingProfile =  
  335.                     ( org.hibernate.mapping.FetchProfile ) itr.next();  
  336.             final FetchProfile fetchProfile = new FetchProfile( mappingProfile.getName() );  
  337.             for ( org.hibernate.mapping.FetchProfile.Fetch mappingFetch : mappingProfile.getFetches() ) {  
  338.                 // resolve the persister owning the fetch  
  339.                 final String entityName = getImportedClassName( mappingFetch.getEntity() );  
  340.                 final EntityPersister owner = entityName == null  
  341.                         ? null  
  342.                         : entityPersisters.get( entityName );  
  343.                 if ( owner == null ) {  
  344.                     throw new HibernateException(  
  345.                             "Unable to resolve entity reference [" + mappingFetch.getEntity()  
  346.                                     + "] in fetch profile [" + fetchProfile.getName() + "]"  
  347.                     );  
  348.                 }  
  349.   
  350.                 // validate the specified association fetch  
  351.                 Type associationType = owner.getPropertyType( mappingFetch.getAssociation() );  
  352.                 if ( associationType == null || !associationType.isAssociationType() ) {  
  353.                     throw new HibernateException( "Fetch profile [" + fetchProfile.getName() + "] specified an invalid association" );  
  354.                 }  
  355.   
  356.                 // resolve the style  
  357.                 final Fetch.Style fetchStyle = Fetch.Style.parse( mappingFetch.getStyle() );  
  358.   
  359.                 // then construct the fetch instance...  
  360.                 fetchProfile.addFetch( new Association( owner, mappingFetch.getAssociation() ), fetchStyle );  
  361.                 ((Loadable) owner).registerAffectingFetchProfile( fetchProfile.getName() );  
  362.             }  
  363.             fetchProfiles.put( fetchProfile.getName(), fetchProfile );  
  364.         }  
  365.   
  366.         this.customEntityDirtinessStrategy = determineCustomEntityDirtinessStrategy();  
  367.         this.currentTenantIdentifierResolver = determineCurrentTenantIdentifierResolver( cfg.getCurrentTenantIdentifierResolver() );  
  368.         this.transactionEnvironment = new TransactionEnvironmentImpl( this );  
  369.         this.observer.sessionFactoryCreated( this );  
  370.     } 

你可能感兴趣的:(Hibernate,JAVA)