Hibernate3源码分析之hibernate.cfg.xml配置文件与SessionFactory类

52 篇文章 0 订阅
1 篇文章 0 订阅
之前的一篇文章 Hibernate3源码分析之SettingsFactory类 只是简单分析一下SettingsFactory类读取Hibernate.cfg.xml 配置文件中property元素,将其赋值给Settings类的实例。hibernate.cfg.xml配置文件中远远不止property元素,还有其它元素,哪么其它元素被解析出来后赋值给了哪些个类的实例呢??? (hibernate.cfg.xml配置文件所对应的dtd文件地址) SessionFactory类为什么只需要一个实例就可以了??? 本文将会尝试解答这些问题

  一、加载hibernate.cfg.xml配置文件并解析property元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.laoyangx;
 
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
 
public class MainConsole {
 
     public static void main(String[] args) {
         
         Configuration conf= new Configuration();
         conf.configure();
         
         SessionFactory factory=conf.buildSessionFactory(); 
     }
}

对这段代码的解析,之前的文章 Hibernate3源码分析之SettingsFactory类 已经分析过了。对Configruation类进行实例化后,接下来就调用该实例的configure()方法,该方法将会读取hibernate.cfg.xml文件

Configuraiton.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public Configuration configure() throws HibernateException {
     configure( "/hibernate.cfg.xml" );    // [1]
     return this ;
}
 
 
 
public Configuration configure(String resource) throws HibernateException {
         log.info( "configuring from resource: " + resource );
         InputStream stream = getConfigurationInputStream( resource );
         return doConfigure( stream, resource );   //[2]
}
 
 
 
protected Configuration doConfigure(InputStream stream, String resourceName) throws HibernateException {
 
         org.dom4j.Document doc;
               
                //省略 ...
         return doConfigure( doc );  //[3]
 
     }
 
 
 
protected Configuration doConfigure(org.dom4j.Document doc) throws HibernateException {
             
                //省略 ...
         addProperties( sfNode );
         parseSessionFactory( sfNode, name );
 
         //省略 ...
 
         return this ;
}

当调用Configruation类的configure方法将会执行许多函数,其顺序如上所示。最终将目标放在addProperties和parseSessionFactory这两个函数上面。先简单看一下hibernate.cfg.xml文件的格式

hibernate.cfg.xml

复制代码
 1  <?xml version="1.0" encoding="UTF-8"?>
 2  <!DOCTYPE hibernate-configuration PUBLIC 
 3      "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
 4      "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
 5  <hibernate-configuration>
 6    <session-factory>
 7        <property name="..."> ... </property>
 8        <property name="..."> ... </property>
 9        <mapping resource="..." />
10       <mapping resource="..." />
11   </session-factory>
12 </hibernate-configuration>
复制代码

HbmBinder类负责解析mapping 元素 每一个hbm.xml文件对应一个Mappings类的实例

[1] addProperties 解析hibernate.cfg.xml配置文件中property元素的,等到调用buildSessionFactory时,将会有SettingsFactory将这些properties赋值给Settings类的实例

[2] parseSessionFactory 解析hibernate.cfg.xml配置文件中除了property元素外的其它元素

二、分析Configruation类的中parseSessionFactory函数

Configuration.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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 );   // [a]
             }
             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 );  // [b]
             }
             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 );  //  [c]
             }
             else if ( "listener" .equals( subelementName ) ) {
                 parseListener( subelement ); //  [d]
             }
             else if ( "event" .equals( subelementName ) ) {
                 parseEvent( subelement ); // [e]
             }
         }
}

       parseSessionFactory函数的源代码如上所示, 可以看出 hibernate.cfg.xml中根元素session-factory元素下的 mapping class-cache collection-cache listener event 这些元素分别由相对应的函数来处理。parseSessionFactory相当于一个dispatcher。

这里只分析一下 解析hibernate.cfg.xml配置文件中mapping元素parseMappingElement函数

Configuration.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
protected void parseMappingElement(Element subelement, String name) {
                 Attribute rsrc = subelement.attribute( "resource" );
         Attribute file = subelement.attribute( "file" );
         Attribute jar = subelement.attribute( "jar" );
         Attribute pkg = subelement.attribute( "package" );
         Attribute clazz = subelement.attribute( "class" );
                
                 //省略 ...
             addFile( file.getValue() );  // [1]
         }
}
 
 
public Configuration addFile(String xmlFile) throws MappingException {
         return addFile( new File( xmlFile ) ); // [2]
}
 
 
public Configuration addFile(File xmlFile) throws MappingException {
             
                 // 省略 ...
     try {
                 //省略 ...
            add( doc ); // [3]
           return this ;
     }
             //省略 ...
}
 
 
protected void add(org.dom4j.Document doc) throws MappingException {
         HbmBinder.bindRoot( doc, createMappings(), CollectionHelper.EMPTY_MAP ); //[4]
}

hibernate.cfg.xml文件最终将会由HbmBinder类来解析完成。哪么mappings元素解析出来,赋值给了谁呢? 答案就在上面代码中的 createMappings()方法里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Mappings createMappings() {
         return new Mappings(
                 classes,
                 collections,
                 tables,
                 namedQueries,
                 namedSqlQueries,
                 sqlResultSetMappings,
                 imports,
                 secondPasses,
                 propertyReferences,
                 namingStrategy,
                 typeDefs,
                 filterDefinitions,
                 extendsQueue,
                 auxiliaryDatabaseObjects,
                 tableNameBinding,
                 columnNameBindingPerTable
             );
}

       实例化一个Mappings类,而传入这些参数正是 Configuraiton中的字段 也就是说Configuration和Mappings是一对多的关系 。搞不清楚为什么在这里只是用Mappings类作为桥梁实例化这些字段,而不添加一个Mappins类的引用。在这里的解答了第一个问题。mapping元素被解析赋值给Configuration类的某些字段,也可以看成是一个hbm.xml文件对应一个mappings类的实例。当执行parseSessionFactory函数之后,就可以调用buildSessionFactory函数来创建SessionFactory了。

SessionFactory实例中存储了一个Settings类的实例和多个Mappings类的实例,数量取决于hbm.xml文件的数量

解答第二个问题:SessionFactory类为什么只需要一个实例就可以了??? Confiuguration 类通过 buildSessionFactory 构造SessionFactory 。SessionFactory是一个会话工厂, 工厂是用来加工、制造和生产的 前提它得有原料和能源。Configuration类读取并解析了hibernate.cfg.xml文件,SessionFactory是由它来构造,它向SessionFactory提供了hibernate.cfg.xml配置文件的信息。当Configuration类加载hibernate.cfg.xml,就算你创建了两个SessionFactory类的实例,它们使用的都是同一个hibernate.cfg.xml配置文件信息,没有必要。除非加载另外一个不同的hibernate.cfg.xml文件。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值