您的位置:首页 > 编程语言 > Java开发

Hibernate源码分析之读取配置文件

2017-07-30 00:00 531 查看
摘要: Hibernate版本为:hibernate-release-4.3.5.Final

重新开始学习一遍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) 方法中解析、处理与安全相关的属性和值。

至此,框架启动时相关的配置文件(映射文件除外)加载过程已经完成,具体可以详细查看源代码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java Hibernate