本节要学习一下Hibernate的配置文件的具体加载、解析的过程,以及涉及到的相关代码,思路是建立一个简单的java项目,配置一个hbm文件,启动后,跟踪调试加载解析hbm的过程,学习相关的代码。
搭建项目后,将所需jar放入java项目的lib目录,在Hibernate的手册中说明此处也可以使用Maven来设置依赖jar,我这里还是使用比较原始的方式。直接建立一个lib目录放置所需要的jar包,然后设置classpath即可。
参考Hibernate手册中所说的,解释一下.hbm中几个具体配置项的相关注意事项。
property中包含name、type、column 这3个常用的属性。
如:
<property name="date" type="timestamp" column="EVENT_DATE"/> <property name="title"/>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)。
因此我们的主方法中使用的是推荐的方法。
相关推荐
这些文件可能详细解析了如何配置和使用二级缓存,比如使用EHCache或Infinispan。 3. **扩展功能(Hibernate Extends)** `hibernate_extends_1`和`hibernate_extends_3`可能涉及到Hibernate的继承映射和扩展机制。...
《Hibernate源码解析(一)》 在Java开发领域,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。深入理解Hibernate的源码,不仅可以帮助开发者更好地运用该工具,还能提升对Java编程和...
- org.hibernate.cfg:配置相关,包括配置文件解析、实体类元数据获取等。 - org.hibernate.engine:实现数据库会话、查询执行、事务管理等功能。 - org.hibernate.persister:负责对象持久化逻辑,包括实体类的...
标签中的“源码”可能指的是在实现SSH2和Hibernate集成时涉及的Java源代码,这包括实体类、DAO(数据访问对象)层、Service层以及配置文件等。开发者通常会编写实体类来映射数据库表,DAO层使用Hibernate API进行...
Hibernate的启动涉及配置文件解析、SessionFactory的创建、实体类扫描等多个环节。首先,通过Configuration类读取hibernate.cfg.xml,解析配置信息,然后建立SessionFactory。SessionFactory的构建过程中,会加载...
标题"传智播客hibernate源码"暗示了这是一个关于Hibernate框架的源代码学习资源,可能包含了对Hibernate框架内部机制的深入解析,以及如何在实际项目中应用Hibernate的相关示例。 描述中的内容重复,进一步确认了这...
**hibernate源码分析:启动过程** 在深入探讨Hibernate启动过程之前,首先需要了解Hibernate是什么。Hibernate是一个开源的对象关系映射(ORM)框架,它为Java开发人员提供了一种在Java应用程序中操作数据库的方式...
在压缩包中,"hibernate-3.1源码"可能是包含整个框架的所有源代码文件。这些文件通常包括核心API、持久化机制、查询语言(HQL)解析器、缓存管理、事务处理、类型转换等模块。通过这些源码,我们可以学习到以下关键...
标题"hibernate源码 直接使用"表明我们将探讨的是Hibernate框架的源代码,以及如何直接在项目中应用这些源代码。Hibernate是一个流行的Java ORM(对象关系映射)框架,它简化了数据库操作,将数据库交互转化为面向...
在本篇《Hibernate源码解析(二)》中,我们将深入探讨Hibernate这一强大的Java对象关系映射(ORM)框架的内部工作原理。这篇博客旨在帮助开发者更好地理解Hibernate的核心机制,以便于更高效地利用它来处理数据库...
Hibernate 的配置可以通过多种方式实现,包括配置文件、可编程配置和 JNDI绑定。配置文件可以是 XML 文件或 properties 文件,用于指定数据库连接信息、映射文件路径等信息。可编程配置可以在运行时动态生成配置信息...
这个文件可能进一步深入讨论了组合(Composition)和聚合(Aggregation)的概念,以及在Hibernate中如何实现这两种关系。 通过这些章节的源代码,读者可以逐步了解Hibernate的核心概念,如对象关系映射、持久化...
总结,Hibernate源码的学习不仅能帮助开发者理解ORM框架的设计原理,还能提升数据库操作的效率和代码的可维护性。通过对源码的深入研究,我们可以更好地利用Hibernate提供的功能,优化我们的应用,同时也能为自己的...
在Hibernate中,SessionFactory的创建是一个重量级过程,因为它会读取配置文件并解析元数据,生成对应的ClassMetadata和CollectionMetadata。一旦创建,SessionFactory对象应当被长期缓存并重复使用,以提高性能。 ...
源码中的`org.hibernate.hql`包包含了HQL解析器和执行器,对于理解查询处理流程很有帮助。 5. **事务管理**:Hibernate支持JTA和JDBC两种事务管理方式。在`org.hibernate.transaction`包中,可以研究如何在...
在源码中,你可以探索SessionFactory的生成过程,以及如何通过Configuration类读取hibernate.cfg.xml配置文件。Hibernate实体类的生命周期管理,包括持久化、瞬时态、托管态和游离态,都在Session接口的实现中得以...
`Configuration`类是Hibernate配置的核心,它负责读取并解析`hibernate.cfg.xml`和`hibernate.properties`文件中的配置信息,将这些信息转换为`Settings`对象,供`SessionFactory`创建时使用。 #### SessionFactory...
11. **集成开发环境(IDE)**:为了更好地利用Hibernate Tools,需要在Eclipse或IntelliJ IDEA等IDE中安装相应的插件,并配置好相关依赖。 在实际开发中,理解并掌握这些知识点将有助于更有效地使用和定制Hibernate...
在深入探讨Hibernate源码之前,...通过深入学习Hibernate源码,我们可以更好地理解其工作原理,优化数据库操作,提高应用性能。同时,对源码的了解也有助于我们解决实际开发中遇到的问题,定制更适合项目需求的功能。
4. **缓存配置**:在Hibernate中,可以通过XML配置文件或注解来配置缓存。这包括设置缓存策略(读/写、非严格读/写、只读等)、指定缓存区域以及选择缓存提供商。 5. **缓存同步**:为了确保数据一致性,Hibernate...