`
bsr1983
  • 浏览: 1100808 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

学习Hibernate源码三_Hibernate中的配置文件解析

 
阅读更多

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

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

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

      1)关于property元素

      property中包含nametypecolumn 3个常用的属性。

   如:

 

<property name="date" type="timestamp" column="EVENT_DATE"/>
<property name="title"/>
   name属性用来设置访问对应的映射类中对应属性值的gettersetter方法,有时候可以只配置一个name属性,typecolumn可以省略。上述例子中的type并不是java的数据类型,也不是SQL数据库的类型,而是被称为hibernate映射类型,它是用来在Java数据类型和SQL数据类型之间做转换的。如果type属性未定义,则Hibernate会尝试确定正确的映射类型来进行转换。在某些情况下,这种使用java类文件反射的自动检测可能没有你所期望和需要的类型,例如上述的date属性,Hibernate不能确定这里的java.util.Date应该映射为SQL的哪种类型,是datetimestamp还是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();

 

 

查看Configurationconfigure()方法,代码如下:

 

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种类型中的一种resourcefilejarpackageclass对于每种资源这里都有不同的加载方式,

查看每一类资源对应的加载方法,最终会发现他们还是会以一种输入流的方式加载到一个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 );
            }
         }
      }
  }

 

通过调用JPAMetadataProvidergetXMLContext()方法获取到一个XMLContext,调用XMLContextpublic 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)

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

 

 

2
0
分享到:
评论

相关推荐

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (1)

    12.6.16 编写Spring和Hibernate的配置文件spring-config.xml 12.6.17 编写web.xml 12.6.18 验证示例 12.7 小结 第四篇 J2EE项目案例精选 第十三章 网上调查系统 13.1 系统概述 13.2 需求分析 13.2.1 系统用例图 ...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (3)

    12.6.16 编写Spring和Hibernate的配置文件spring-config.xml 12.6.17 编写web.xml 12.6.18 验证示例 12.7 小结 第四篇 J2EE项目案例精选 第十三章 网上调查系统 13.1 系统概述 13.2 需求分析 13.2.1 系统用例图 ...

    java源码包---java 源码 大量 实例

    通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥,通常应对私钥加密后再保存、如何从...

    JAVA上百实例源码以及开源项目源代码

    通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥,通常应对私钥加密后再保存、如何从...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (2)

    12.6.16 编写Spring和Hibernate的配置文件spring-config.xml 12.6.17 编写web.xml 12.6.18 验证示例 12.7 小结 第四篇 J2EE项目案例精选 第十三章 网上调查系统 13.1 系统概述 13.2 需求分析 13.2.1 系统用例图 ...

    spring_MVC源码

    弃用了struts,用spring mvc框架做了几个项目,感觉都不错,而且使用了注解方式,可以省掉一大堆配置文件。本文主要介绍使用注解方式配置的spring mvc,之前写的spring3.0 mvc和rest小例子没有介绍到数据层的内容,...

    JAVA上百实例源码以及开源项目

    通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥,通常应对私钥加密后再保存、如何从...

    java源码包2

     Java实现HTTP连接与浏览,Java源码下载,输入html文件地址或网址,显示页面和HTML源文件,一步步的实现过程请下载本实例的Java源码,代码中包括丰富的注释,对学习有帮助。 Java实现的FTP连接与数据浏览程序 1个...

    java源码包JSP实例源码JAVA开发源码65个合集.zip

    java源码包JSP实例源码JAVA开发源码65个合集: Java自定义光标程序源码.rar Jav动画图标源码(显示GIF图像).rar JLoading Java版的Mp3下载工具.rar JSP 动态数据菜单.rar JSP 学生管理系统(全部代码+数据库).rar ...

    DWR.xml配置文件说明书(含源码)

    从java中传递null值到javascript是没有任何危险性的,所以DWR将这个作为默认的converter,所以你自己不用再把这个converter添加到配置文件的部分中去. 基本类型的converter转换int,boolean,double等.当然还包括对应的...

    java源码包3

     Java实现HTTP连接与浏览,Java源码下载,输入html文件地址或网址,显示页面和HTML源文件,一步步的实现过程请下载本实例的Java源码,代码中包括丰富的注释,对学习有帮助。 Java实现的FTP连接与数据浏览程序 1个...

    java源码包4

     Java实现HTTP连接与浏览,Java源码下载,输入html文件地址或网址,显示页面和HTML源文件,一步步的实现过程请下载本实例的Java源码,代码中包括丰富的注释,对学习有帮助。 Java实现的FTP连接与数据浏览程序 1个...

    基于SpringMVC+Hibernate4的考勤管理系统+.zip

    spring-beans-4.0.0.RELEASE.jar 所有应用都要用到的,它包含访问配置文件、创建和管理bean spring-context-4.0.0.RELEASE.jar Spring 核心提供了大量扩展 spring-core-4.0.0.RELEASE.jar Spring 框架基本的核心工具...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    从文件中读取数字证书,生成文件输入流,输入文件为c:/mycert.cer,获取一个处理X.509证书的证书工厂…… Java+ajax写的登录实例 1个目标文件 内容索引:Java源码,初学实例,ajax,登录 一个Java+ajax写的登录实例,附有...

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    从文件中读取数字证书,生成文件输入流,输入文件为c:/mycert.cer,获取一个处理X.509证书的证书工厂…… Java+ajax写的登录实例 1个目标文件 内容索引:Java源码,初学实例,ajax,登录 一个Java+ajax写的登录实例,附有...

    java源码包33个实例源码阳光酒店管理系统手机游戏J2ME毕业设计书籍管理系统网络电视源代码TV

    java源码包33个实例源码,可以做为你的学习设计参考,详细实例源码如下: 一个支持servlet的web服务器.rar 一个较初级的EJB商业应用的例子.rar 一款Java网络格斗游戏源码.rar 业务流程管理(BPM)和工作流系统 ...

    Java通用代码生成实用程序XDoclet(源码包)

    XDoclet 是一个通用的代码生成实用程序,是一个扩展的Javadoc Doclet引擎,它允许您使用象 JavaDoc 标记之 类的东西来向诸如类、方法...这样,我们就能在使用ant编译工程的同时,使Xdoclet为我们生成相关的配置文件了。

    《程序天下:J2EE整合详解与典型案例》光盘源码

    12.6.16 编写Spring和Hibernate的配置文件spring-config.xml 12.6.17 编写web.xml 12.6.18 验证示例 12.7 小结 第四篇 J2EE项目案例精选 第十三章 网上调查系统 13.1 系统概述 13.2 需求分析 13.2.1 系统用例图 ...

    java面试题

    Hibernate源码中几个包的作用简要介绍 65 72. struts 66 72.1. struts 简介 66 72.2. STRUTS的应用(如STRUTS架构) 66 72.3. 请写出Struts的工作原理、工作机制 67 72.4. struts的处理流程。 67 72.5. Struts 2框架...

Global site tag (gtag.js) - Google Analytics