Hibernate源码分析之读取配置文件
2017-07-30 00:00
531 查看
摘要: Hibernate版本为:hibernate-release-4.3.5.Final
重新开始学习一遍Hibernate框架,首先从读取配置文件开始。
请看一段使用Hibernate的代码:
先看看 Configuration 对象的 configure() 方法:
(1)configure方法有多个重载的方法,对于未指定 hibernate.cfg.xml 文件位置时,会默认加载src根目录下名字为 hibernate.cfg.xml 的文件;
(2)假如项目中存在多个配置文件,你想统一管理配置文件,可以将配置文件放置你指定的任何地方。在初始化的时候,记得传入你hibernate配置文件的位置,以String字符串形式,传入 configure(String)。
接下来看看 configure(String) 方法中具体做了什么:
把配置文件加载到输入流 stream 后,作为入参传入到 doConfigure(InputStream,String) 中,处理具体的解析任务:
在doConfigure方法中,使用SAXReader解析指定的配置文件,把解析出来的结果---Document对象实例,作为入参,传给同名重载方法 doConfigure(Document)中:
该方法主要完成如下工作:
1.获取 hibernate.cfg.xml 中根节点(hibernate-configuration)的子节点---<session-factory>节点,如果配置属性name,则读取属性值,存入成员变量Properties实例中;
2.接着处理<property>节点,传入<session-factory>节点到 addProperties(Element) 中:
首先取到父节点,也就是<session-factory>节点下的所有<property>节点,然后遍历取出属性名称和属性值,放入成员变量properties中。仔细一点的童鞋可以看到处理细节:对属性值进行trim操作,对不是以hibernate开头的属性名称,自动拼接前缀:'hibernate.'。
在 addProperties(Element) 方法的最后使用到了 Enviroment 对象,在该类被加载前,会读取src根目录下的 hibernate.properties 配置文件(非必需):
3.然后在 parseSessionFactory(Element,String) 中处理解析<session-factory>节点中其他的子节点:
如上所示,也是首先获取<session-factory>节点下所有的子节点,然后按照节点的名字,使用对应解析器处理不同的较复杂的子节点:在 parseMappingElement(Element,String) 中详细处理<mapping>节点。对于简单的子节点如:<class-cache>和<collection-cache>,直接获取属性名称和值,设置到对应的成员变量中去。
4.最后,如果<session-factory>节点存在安全相关的配置节点---<security>节点,则在 parseSecurity(Element) 方法中解析、处理与安全相关的属性和值。
至此,框架启动时相关的配置文件(映射文件除外)加载过程已经完成,具体可以详细查看源代码。
重新开始学习一遍Hibernate框架,首先从读取配置文件开始。
请看一段使用Hibernate的代码:
private static SessionFactory sessionFactory; private static Configuration configuration = new Configuration(); private static ServiceRegistry serviceRegistry; static { try { configuration.configure(); //.configure("com/rumo/config/myhibernate.cfg.xml"); serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build(); sessionFactory = configuration.buildSessionFactory(serviceRegistry); } catch (Exception e) { e.printStackTrace(); } }
先看看 Configuration 对象的 configure() 方法:
public Configuration configure() throws HibernateException { configure( "/hibernate.cfg.xml" ); return this; }
(1)configure方法有多个重载的方法,对于未指定 hibernate.cfg.xml 文件位置时,会默认加载src根目录下名字为 hibernate.cfg.xml 的文件;
(2)假如项目中存在多个配置文件,你想统一管理配置文件,可以将配置文件放置你指定的任何地方。在初始化的时候,记得传入你hibernate配置文件的位置,以String字符串形式,传入 configure(String)。
接下来看看 configure(String) 方法中具体做了什么:
public Configuration configure(String resource) throws HibernateException { InputStream stream = getConfigurationInputStream( resource ); return doConfigure( stream, resource ); }
把配置文件加载到输入流 stream 后,作为入参传入到 doConfigure(InputStream,String) 中,处理具体的解析任务:
protected Configuration doConfigure(InputStream stream, String resourceName) throws HibernateException { try { ErrorLogger errorLogger = new ErrorLogger( resourceName ); Document document = xmlHelper.createSAXReader( errorLogger, entityResolver ) .read( new InputSource( stream ) ); //... doConfigure( document ); } catch (DocumentException e) { throw new HibernateException( "Could not parse configuration: " + resourceName, e ); } finally { //... } return this; }
在doConfigure方法中,使用SAXReader解析指定的配置文件,把解析出来的结果---Document对象实例,作为入参,传给同名重载方法 doConfigure(Document)中:
protected Configuration doConfigure(Document doc) throws HibernateException { Element sfNode = doc.getRootElement().element( "session-factory" ); String name = sfNode.attributeValue( "name" ); if ( name != null ) { properties.setProperty( Environment.SESSION_FACTORY_NAME, name ); } addProperties( sfNode ); parseSessionFactory( sfNode, name ); Element secNode = doc.getRootElement().element( "security" ); if ( secNode != null ) { parseSecurity( secNode ); } return this; }
该方法主要完成如下工作:
1.获取 hibernate.cfg.xml 中根节点(hibernate-configuration)的子节点---<session-factory>节点,如果配置属性name,则读取属性值,存入成员变量Properties实例中;
2.接着处理<property>节点,传入<session-factory>节点到 addProperties(Element) 中:
private void addProperties(Element parent) { Iterator itr = parent.elementIterator( "property" ); while ( itr.hasNext() ) { Element node = (Element) itr.next(); String name = node.attributeValue( "name" ); String value = node.getText().trim(); properties.setProperty( name, value ); if ( !name.startsWith( "hibernate" ) ) { properties.setProperty( "hibernate." + name, value ); } } Environment.verifyProperties( properties ); }
首先取到父节点,也就是<session-factory>节点下的所有<property>节点,然后遍历取出属性名称和属性值,放入成员变量properties中。仔细一点的童鞋可以看到处理细节:对属性值进行trim操作,对不是以hibernate开头的属性名称,自动拼接前缀:'hibernate.'。
在 addProperties(Element) 方法的最后使用到了 Enviroment 对象,在该类被加载前,会读取src根目录下的 hibernate.properties 配置文件(非必需):
static { //... try { InputStream stream = ConfigHelper.getResourceAsStream( "/hibernate.properties" ); try { GLOBAL_PROPERTIES.load(stream); } //... } catch (HibernateException he) { LOG.propertiesNotFound(); } //... }
3.然后在 parseSessionFactory(Element,String) 中处理解析<session-factory>节点中其他的子节点:
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 ); } } }
如上所示,也是首先获取<session-factory>节点下所有的子节点,然后按照节点的名字,使用对应解析器处理不同的较复杂的子节点:在 parseMappingElement(Element,String) 中详细处理<mapping>节点。对于简单的子节点如:<class-cache>和<collection-cache>,直接获取属性名称和值,设置到对应的成员变量中去。
4.最后,如果<session-factory>节点存在安全相关的配置节点---<security>节点,则在 parseSecurity(Element) 方法中解析、处理与安全相关的属性和值。
至此,框架启动时相关的配置文件(映射文件除外)加载过程已经完成,具体可以详细查看源代码。
相关文章推荐
- Spring源码分析:Bean加载流程概览及配置文件读取
- Spring 源码分析:Bean 加载流程概览及配置文件读取
- 【Spring源码分析】配置文件读取流程
- 【mybatis源码分析】原理分析之三:初始化(配置文件读取和解析)
- Hibernate3源码分析之hibernate.cfg.xml配置文件与SessionFactory类
- hibernate3.0源码分析:配置文件的获取
- Spring源码分析:配置文件读取流程
- Paoding Rose源码分析1-读取Rose配置文件
- log4j源码简要分析 | 读取配置文件
- Hibernate3源码分析之hibernate.cfg.xml配置文件与SessionFactory类
- hibernate源码-配置文件加载过程分析
- mybatis底层源码分析之--配置文件读取和解析
- Spring源码分析:Bean加载流程概览及配置文件读取
- Heritrix源码分析(二) 配置文件order.xml介绍
- Java 工具(jmap,jstack)在linux上的源码分析(六) -F 参数 读取动态链接共享库文件中的符号表
- levelDB源码分析-SSTable:.sst文件构建与读取
- SSH读取applicationContext.xml配置文件测试hibernate方法
- nginx 源码学习笔记(十三)——文件读写和配置文件读取
- C# 读取保存App.config配置文件的完整源码参考(转)
- nginx 源码学习笔记(十三)——文件读写和配置文件读取