`
bsr1983
  • 浏览: 1124016 次
  • 性别: 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
分享到:
评论

相关推荐

    hibernate源码下载

    这些文件可能详细解析了如何配置和使用二级缓存,比如使用EHCache或Infinispan。 3. **扩展功能(Hibernate Extends)** `hibernate_extends_1`和`hibernate_extends_3`可能涉及到Hibernate的继承映射和扩展机制。...

    Hibernate源码解析(一)

    《Hibernate源码解析(一)》 在Java开发领域,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。深入理解Hibernate的源码,不仅可以帮助开发者更好地运用该工具,还能提升对Java编程和...

    hibernate_in_action 源码

    - org.hibernate.cfg:配置相关,包括配置文件解析、实体类元数据获取等。 - org.hibernate.engine:实现数据库会话、查询执行、事务管理等功能。 - org.hibernate.persister:负责对象持久化逻辑,包括实体类的...

    hibernate_____实现ssh2用的hibernate

    标签中的“源码”可能指的是在实现SSH2和Hibernate集成时涉及的Java源代码,这包括实体类、DAO(数据访问对象)层、Service层以及配置文件等。开发者通常会编写实体类来映射数据库表,DAO层使用Hibernate API进行...

    hibernate源码分析

    Hibernate的启动涉及配置文件解析、SessionFactory的创建、实体类扫描等多个环节。首先,通过Configuration类读取hibernate.cfg.xml,解析配置信息,然后建立SessionFactory。SessionFactory的构建过程中,会加载...

    传智播客hibernate源码

    标题"传智播客hibernate源码"暗示了这是一个关于Hibernate框架的源代码学习资源,可能包含了对Hibernate框架内部机制的深入解析,以及如何在实际项目中应用Hibernate的相关示例。 描述中的内容重复,进一步确认了这...

    hibernate源码分析一_启动过程_

    **hibernate源码分析:启动过程** 在深入探讨Hibernate启动过程之前,首先需要了解Hibernate是什么。Hibernate是一个开源的对象关系映射(ORM)框架,它为Java开发人员提供了一种在Java应用程序中操作数据库的方式...

    hibernate_3.1源码

    在压缩包中,"hibernate-3.1源码"可能是包含整个框架的所有源代码文件。这些文件通常包括核心API、持久化机制、查询语言(HQL)解析器、缓存管理、事务处理、类型转换等模块。通过这些源码,我们可以学习到以下关键...

    hibernate源码 直接使用

    标题"hibernate源码 直接使用"表明我们将探讨的是Hibernate框架的源代码,以及如何直接在项目中应用这些源代码。Hibernate是一个流行的Java ORM(对象关系映射)框架,它简化了数据库操作,将数据库交互转化为面向...

    Hibernate源码解析(二)

    在本篇《Hibernate源码解析(二)》中,我们将深入探讨Hibernate这一强大的Java对象关系映射(ORM)框架的内部工作原理。这篇博客旨在帮助开发者更好地理解Hibernate的核心机制,以便于更高效地利用它来处理数据库...

    hibernate源码分析过程

    Hibernate 的配置可以通过多种方式实现,包括配置文件、可编程配置和 JNDI绑定。配置文件可以是 XML 文件或 properties 文件,用于指定数据库连接信息、映射文件路径等信息。可编程配置可以在运行时动态生成配置信息...

    hibernate_persistence第02-16章书中源码

    这个文件可能进一步深入讨论了组合(Composition)和聚合(Aggregation)的概念,以及在Hibernate中如何实现这两种关系。 通过这些章节的源代码,读者可以逐步了解Hibernate的核心概念,如对象关系映射、持久化...

    hibernate源码

    总结,Hibernate源码的学习不仅能帮助开发者理解ORM框架的设计原理,还能提升数据库操作的效率和代码的可维护性。通过对源码的深入研究,我们可以更好地利用Hibernate提供的功能,优化我们的应用,同时也能为自己的...

    传智播客hibernate源码.rar

    在Hibernate中,SessionFactory的创建是一个重量级过程,因为它会读取配置文件并解析元数据,生成对应的ClassMetadata和CollectionMetadata。一旦创建,SessionFactory对象应当被长期缓存并重复使用,以提高性能。 ...

    hibernate3.2_src官方源码

    源码中的`org.hibernate.hql`包包含了HQL解析器和执行器,对于理解查询处理流程很有帮助。 5. **事务管理**:Hibernate支持JTA和JDBC两种事务管理方式。在`org.hibernate.transaction`包中,可以研究如何在...

    Struts,Spring,Hibernate源码包

    在源码中,你可以探索SessionFactory的生成过程,以及如何通过Configuration类读取hibernate.cfg.xml配置文件。Hibernate实体类的生命周期管理,包括持久化、瞬时态、托管态和游离态,都在Session接口的实现中得以...

    hibernate源码分析一[启动过程]

    `Configuration`类是Hibernate配置的核心,它负责读取并解析`hibernate.cfg.xml`和`hibernate.properties`文件中的配置信息,将这些信息转换为`Settings`对象,供`SessionFactory`创建时使用。 #### SessionFactory...

    hibernate tools源码运行或修改需要的jar

    11. **集成开发环境(IDE)**:为了更好地利用Hibernate Tools,需要在Eclipse或IntelliJ IDEA等IDE中安装相应的插件,并配置好相关依赖。 在实际开发中,理解并掌握这些知识点将有助于更有效地使用和定制Hibernate...

    精通hibernate源码ch2

    在深入探讨Hibernate源码之前,...通过深入学习Hibernate源码,我们可以更好地理解其工作原理,优化数据库操作,提高应用性能。同时,对源码的了解也有助于我们解决实际开发中遇到的问题,定制更适合项目需求的功能。

    Hibernate教程25_Hibernate缓存

    4. **缓存配置**:在Hibernate中,可以通过XML配置文件或注解来配置缓存。这包括设置缓存策略(读/写、非严格读/写、只读等)、指定缓存区域以及选择缓存提供商。 5. **缓存同步**:为了确保数据一致性,Hibernate...

Global site tag (gtag.js) - Google Analytics