Hibernate3 : org.hibernate.cfg.Configuration 解析
? 第一次寫文章,不好的地方,請口下留情哈。
? org.hibernate.cfg.Configurations 根據 xml 文件配置整個工作過程中所需要的參數。一般
我們會用 Configuration cfg = new Configuration().configure(); 創建一個配置類。那么,這句話到底做了什么呢?
? 首先, new Configuration() 會做些什么呢?我們來看他的源碼:
??
?
protected Configuration(SettingsFactory settingsFactory) {
??????? System.out.println("Configuration(SettingsFactory settingsFactory)");
??????? this.settingsFactory = settingsFactory;
??????? reset();
??? }
// 默認構造函數,先 new SettingsFactory() , 然后調用
//protected Configuration(SettingsFactory settingsFactory)
???
public Configuration() {
??????? this(new SettingsFactory());
}
reset() 初始化了很多變量,感興趣的可以去看源代碼,沒有什么特別的地方。
?
? 接著,調用 configure() 方法!
public Configuration configure() throws HibernateException {
??????? configure("/hibernate.cfg.xml");
??????? return this;
}
可以看出,默認使用 hibernate.cfg.xml 文件,如果想用自定義的文件,可以調用
configure(“….xml”) 方法。
public Configuration configure(String resource) throws HibernateException {
??????? log.debug("configuring from resource: " + resource);
??????? InputStream stream = getConfigurationInputStream(resource);
??????? return doConfigure(stream, resource);
}
根據
getConfigurationInputStream(resource)
得到文件流,
getConfigurationInputStream(resource)
調用
ConfigHelper.getResourceAsStream(resource)
。
public static InputStream getResourceAsStream(String resource) {
????????????? String stripped = resource.startsWith("/") ?
??????????????????????????? resource.substring(1) : resource;
????????????? InputStream stream = null;
????????????? ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
????????????? if (classLoader!=null) {
???????????????????? stream = classLoader.getResourceAsStream( stripped );
????????????? }
//
這里的代碼可能應該是
stream = Environment.class.getResourceAsStream( resource );
?????????????
if ( stream == null ) {
???????????????????? Environment.class.getResourceAsStream( resource );
????????????? }
????????????? if ( stream == null ) {
???????????????????? stream = Environment.class.getClassLoader().getResourceAsStream( stripped );
????????????? }
????????????? if ( stream == null ) {
???????????????????? throw new HibernateException( resource + " not found" );
????????????? }
????????????? return stream;
?????? }
然后
doConfigure(stream, resource)
。
protected Configuration doConfigure(InputStream stream, String resourceName) throws HibernateException {
org.dom4j.Document doc;
??????? try {
??????????? List errors = new ArrayList();
??????????? SAXReader saxReader = xmlHelper.createSAXReader(resourceName, errors, entityResolver);
??????????? doc = saxReader.read(new InputSource(stream));
??????????? if (errors.size() != 0) {
??????????????? throw new MappingException(
??????????????????????? "invalid configuration",
??????????????????????? (Throwable) errors.get(0)
??????????????? );
??????????? }
??????? }
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 ,比較比較。
?
在得到 doc 的值
???????????
doc = saxReader.read(new InputSource(stream));
后,調用 protected Configuration doConfigure(org.dom4j.Document doc) ,這個函數主要是根據 doc 的到配置參數,然后存到 properties 中。
? 先是設置 session-factory 的名字:
Element sfNode = doc.getRootElement().element("session-factory");
??????? String name = sfNode.attributeValue("name");
??????? if (name != null) {
???????????? //
保存到
properties
中!
??????????? properties.setProperty(Environment.SESSION_FACTORY_NAME, name);
??????? }
然后是 addProperties(sfNode) ,把 <property name=" "> </property> 保存到 properties 中。
//
這句話估計又是多余的
properties.setProperty(name, value);
??????????
?if (!name.startsWith("hibernate")) {
??????????????? properties.setProperty("hibernate." + name, value);
??????????? }
接著調用了 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 。
????????????? extractRootAttributes( hmNode, mappings ) 根據 <hibernate-mapping> 的配置,把分析的結果存入 mapping 。
?