Hibernate3 : org.hibernate.cfg.Configuration 解析
<!----> <o:p> </o:p>
第一次写文章,不好的地方,请口下留情哈。
org.hibernate.cfg.Configurations 根据 xml 文件配置整个工作过程中所需要的参数。一般
我们会用 Configuration cfg = new Configuration().configure(); 创建一个配置类。那么,这句话到底做了什么呢?
首先, new Configuration() 会做些什么呢?我们来看他的源码:
protected Configuration(SettingsFactory settingsFactory) {<o:p></o:p>
System.out.println("Configuration(SettingsFactory settingsFactory)");<o:p></o:p>
this.settingsFactory = settingsFactory;<o:p></o:p>
reset();<o:p></o:p>
}<o:p></o:p>
<o:p> </o:p>
// 默认构造函数,先 new SettingsFactory() , 然后调用
//protected Configuration(SettingsFactory settingsFactory)
<o:p> </o:p>
public Configuration() {<o:p></o:p>
this(new SettingsFactory());<o:p></o:p>
}<o:p></o:p>
<o:p> </o:p>
reset() 初始化了很多变量,感兴趣的可以去看源代码,没有什么特别的地方。
接着,调用 configure() 方法!
public Configuration configure() throws HibernateException {<o:p></o:p>
configure("/hibernate.cfg.xml");<o:p></o:p>
return this;<o:p></o:p>
}<o:p></o:p>
可以看出,默认使用 hibernate.cfg.xml 文件,如果想用自定义的文件,可以调用
configure(“….xml”) 方法。
public Configuration configure(String resource) throws HibernateException {<o:p></o:p>
log.debug("configuring from resource: " + resource);<o:p></o:p>
InputStream stream = getConfigurationInputStream(resource);<o:p></o:p>
return doConfigure(stream, resource);<o:p></o:p>
}<o:p></o:p>
根据 getConfigurationInputStream(resource) 得到文件流, getConfigurationInputStream(resource) 调用 ConfigHelper.getResourceAsStream(resource) 。 <o:p> </o:p>
public static InputStream getResourceAsStream(String resource) {<o:p></o:p>
String stripped = resource.startsWith("/") ? <o:p></o:p>
resource.substring(1) : resource;<o:p></o:p>
InputStream stream = null; <o:p></o:p>
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();<o:p></o:p>
if (classLoader!=null) {<o:p></o:p>
stream = classLoader.getResourceAsStream( stripped );<o:p></o:p>
}
// 这里的代码可能应该是 stream = Environment.class.getResourceAsStream( resource );<o:p></o:p>
if ( stream == null ) {<o:p></o:p>
Environment.class.getResourceAsStream( resource );<o:p></o:p>
}<o:p></o:p>
<o:p> </o:p>
if ( stream == null ) {<o:p></o:p>
stream = Environment.class.getClassLoader().getResourceAsStream( stripped );<o:p></o:p>
}<o:p></o:p>
if ( stream == null ) {<o:p></o:p>
throw new HibernateException( resource + " not found" );<o:p></o:p>
}<o:p></o:p>
return stream;<o:p></o:p>
}<o:p></o:p>
然后 doConfigure(stream, resource) 。 <o:p> </o:p>
protected Configuration doConfigure(InputStream stream, String resourceName) throws HibernateException {<o:p></o:p>
org.dom4j.Document doc;<o:p></o:p>
try {<o:p></o:p>
List errors = new ArrayList();<o:p></o:p>
SAXReader saxReader = xmlHelper.createSAXReader(resourceName, errors, entityResolver);<o:p></o:p>
doc = saxReader.read(new InputSource(stream));<o:p></o:p>
if (errors.size() != 0) {<o:p></o:p>
throw new MappingException(<o:p></o:p>
"invalid configuration",<o:p></o:p>
(Throwable) errors.get(0)<o:p></o:p>
);<o:p></o:p>
}<o:p></o:p>
}<o:p></o:p>
entityResolver 在初始值为 entityResolver = XMLHelper.DEFAULT_DTD_RESOLVER ; 在 reset() 的时候设置的。 XMLHelper.DEFAULT_DTD_RESOLVE 在 XMLHelper 默认是 XMLHelper.DEFAULT_DTD_RESOLVER= new DTDEntityResolver() ; DTDEntityResolver 是用来加载 dtd 文件的。别跟我说你不知道 dtd 是什么东西?它有 3 种加载方式:
1. 文件路径以 http://hibernate.sourceforge.net/ 开头的文件,如
http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd ,
它会把 http://hibernate.sourceforge.net 去掉,加上 org/hibernate/ ,文件路径为
org/hibernate/hibernate-configuration-3.0.dtd ,然后加载这个文件。
2. 文件路径以 file:// 开头的文件,如
file://hibernate-configuration-3.0.dtd ,
它会把 file:// 去掉,路径为 hibernate-configuration-3.0.dtd ,然后加载这个文件。
3. 如果没有以上 2 种情况,则直接加载。就是路径名没有修改过。
整个过程在 public InputSource resolveEntity(String publicId, String systemId) 中实现。
systemId 就是 dtd 的路径。大家可以去看看 SAXReader 类自带的
protected static class SAXEntityResolver ,比较比较。
<o:p> </o:p>
在得到 doc 的值
doc = saxReader.read(new InputSource(stream));<o:p></o:p>
后,调用 protected Configuration doConfigure(org.dom4j.Document doc) ,这个函数主要是根据 doc 的到配置参数,然后存到 properties 中。
先是设置 session-factory 的名字:
<o:p> </o:p>
Element sfNode = doc.getRootElement().element("session-factory");<o:p></o:p>
String name = sfNode.attributeValue("name");<o:p></o:p>
if (name != null) {<o:p></o:p>
// 保存到 properties 中! <o:p> </o:p>
properties.setProperty(Environment.SESSION_FACTORY_NAME, name);<o:p></o:p>
}<o:p></o:p>
<o:p> </o:p>
然后是 addProperties(sfNode) ,把 <property name=" "> </property> 保存到 properties 中。
// 这句话估计又是多余的 <o:p> </o:p>
properties.setProperty(name, value);<o:p></o:p>
<o:p> </o:p>
if (!name.startsWith("hibernate")) {<o:p></o:p>
properties.setProperty("hibernate." + name, value);<o:p></o:p>
}
接着调用了 parseSessionFactory(sfNode, name) ,把 mapping , class-cache , collection-cache , listener , event 等配置保存。到底它保存到哪,我也不全知道,只看了
protected void parseMappingElement(Element subelement, String name), 根据配置加载了 mapping 的文件,最后使用 HbmBinder : public static void bindRoot(Document doc, Mappings mappings, java.util.Map inheritedMetas) 保存。 bindRoot 是对 mapping 中的 xml 文件进行解析。
HbmBinder 和 Configuration 都有 2000 行以上的代码,在 Hibernate 中有很重要的地位。 Configuration 使用 .cfg.xml ,而 HbmBinder 则使用了 .hbm.xml 。
<o:p> </o:p>
extractRootAttributes( hmNode, mappings ) 根据 <hibernate-mapping> 的配置,把分析的结果存入 mapping 。
<o:p> </o:p>
<o:p> </o:p>
<o:p> </o:p>
<o:p> </o:p>
<o:p> </o:p>
<o:p> </o:p>