Hibernate源码解读——启动
作为javar的必学框架,我相信Hibernate源码也是被研究过无数次了。不过,别人研究过不代表我就不需要看了。
这里我以我的视野简单的过一遍。各位iteye的朋友有时间可以看看。如何已经很熟悉这个了就不用看了,否则看也是浪费时间。我研究的方法非常简单,就是反复读源码,一遍不行,二遍,或者三遍。。。
从Hibernate源码看它的启动过程:
Hibernate的启动是从Configuration开始的。Configuration既是它的配置中心,也是它的启动最初点。
Configuration提供了几个重载的configure方法,用来读取配置,默认,当然就是hibernate.cfg.xml。
configure调用doConfigure,返回Configuration。
doConfigure(org.dom4j.Document doc)很重要:
protected Configuration doConfigure(org.dom4j.Document doc) throws HibernateException { //获取session-factory节点sfNode Element sfNode = doc.getRootElement().element( "session-factory" ); String name = sfNode.attributeValue( "name" ); if ( name != null ) { properties.setProperty( Environment.SESSION_FACTORY_NAME, name ); } //处理sfNode的子节点property addProperties( sfNode ); //处理sfNode的其他子节点,主要是mapping、listener、event parseSessionFactory( sfNode, name ); Element secNode = doc.getRootElement().element( "security" ); if ( secNode != null ) { parseSecurity( secNode );//处理doc的其他子节点,security,一般用的少 } return this; }
mapping 是关键,类似下面的配置
<mapping resource="com/bjsxt/drp/business/itemmgr/model/DataDict.hbm.xml"/>
protected void parseMappingElement(Element subelement, String name) { Attribute rsrc = subelement.attribute( "resource" ); Attribute file = subelement.attribute( "file" ); Attribute jar = subelement.attribute( "jar" ); Attribute pkg = subelement.attribute( "package" ); Attribute clazz = subelement.attribute( "class" ); addResource( rsrc.getValue() ); addJar( new File( jar.getValue() ) ); addFile( file.getValue() ); }
常用的当然就是addResource,它调用addInputStream,然后是add(org.dom4j.Document doc),然后是HbmBinder.bindRoot( doc, createMappings(), CollectionHelper.EMPTY_MAP );
HbmBinder相当重要,他处理了Xxx.hbm.xml的各种配置;
——Walks an XML mapping document and produces the Hibernate configuration-time metamodel (the classes in the mapping)
bindRoot首先处理package属性,然后是其下面的各种元素:
filter-def
typedef
class: 通过bindRootClass-bindRootPersistentClassCommonValues处理class下的 property元素等
subclass
typedef
query
sql-query
import
database-object
else if ( "class".equals( elementName ) ) { RootClass rootclass = new RootClass(); bindRootClass( element, rootclass, mappings, inheritedMetas ); mappings.addClass( rootclass ); } ---->>> public static void bindRootClass(Element node, RootClass rootClass, Mappings mappings, java.util.Map inheritedMetas) throws MappingException { bindClass( node, rootClass, mappings, inheritedMetas ); inheritedMetas = getMetas( node, inheritedMetas, true ); // get meta's from <class> bindRootPersistentClassCommonValues( node, inheritedMetas, mappings, rootClass ); }
继续跟踪,我们发现,类似 Xxx.hbm.xml的配置,里面的class元素,都被放到了 RootClass 里面:
public class RootClass extends PersistentClass implements TableOwner
它是一个实际对数据进行封装的类,主要是封装了下面的 属性,及对应的setter、getter方法。
private Property identifierProperty; //may be final private KeyValue identifier; //may be final private Property version; //may be final private boolean polymorphic; private String cacheConcurrencyStrategy; private String cacheRegionName; private boolean lazyPropertiesCacheable = true; private Value discriminator; //may be final private boolean mutable = true; private boolean embeddedIdentifier = false; // may be final private boolean explicitPolymorphism; private Class entityPersisterClass; private boolean forceDiscriminator = false; private String where; private Table table; private boolean discriminatorInsertable = true; private int nextSubclassId = 0;
PersistentClass 也是很重要,——Mapping for an entity
bindClass主要对 class里面的属性进行处理;
而bindRootPersistentClassCommonValues是对class下元素进行处理;
bindRootPersistentClassCommonValues很重要,二级缓存标签cache 也是在这里进行处理的!
private static void bindRootPersistentClassCommonValues(Element node, java.util.Map inheritedMetas, Mappings mappings, RootClass entity) throws MappingException { // DB-OBJECTNAME Attribute schemaNode = node.attribute( "schema" ); String schema = schemaNode == null ? mappings.getSchemaName() : schemaNode.getValue(); Attribute catalogNode = node.attribute( "catalog" ); String catalog = catalogNode == null ? mappings.getCatalogName() : catalogNode.getValue(); Table table = mappings.addTable( schema, catalog, getClassTableName( entity, node, schema, catalog, null, mappings ), getSubselect( node ), entity.isAbstract() != null && entity.isAbstract().booleanValue() ); entity.setTable( table ); bindComment(table, node); // MUTABLE Attribute mutableNode = node.attribute( "mutable" ); entity.setMutable( ( mutableNode == null ) || mutableNode.getValue().equals( "true" ) ); // WHERE Attribute whereNode = node.attribute( "where" ); if ( whereNode != null ) entity.setWhere( whereNode.getValue() ); // CHECK Attribute chNode = node.attribute( "check" ); if ( chNode != null ) table.addCheckConstraint( chNode.getValue() ); // POLYMORPHISM Attribute polyNode = node.attribute( "polymorphism" ); entity.setExplicitPolymorphism( ( polyNode != null ) && polyNode.getValue().equals( "explicit" ) ); // ROW ID Attribute rowidNode = node.attribute( "rowid" ); if ( rowidNode != null ) table.setRowId( rowidNode.getValue() ); Iterator subnodes = node.elementIterator(); while ( subnodes.hasNext() ) { Element subnode = (Element) subnodes.next(); String name = subnode.getName(); if ( "id".equals( name ) ) { // ID bindSimpleId( subnode, entity, mappings, inheritedMetas ); } else if ( "composite-id".equals( name ) ) { // COMPOSITE-ID bindCompositeId( subnode, entity, mappings, inheritedMetas ); } else if ( "version".equals( name ) || "timestamp".equals( name ) ) { // VERSION / TIMESTAMP bindVersioningProperty( table, subnode, mappings, name, entity, inheritedMetas ); } else if ( "discriminator".equals( name ) ) { // DISCRIMINATOR bindDiscriminatorProperty( table, entity, subnode, mappings ); } else if ( "cache".equals( name ) ) { entity.setCacheConcurrencyStrategy( subnode.attributeValue( "usage" ) ); entity.setCacheRegionName( subnode.attributeValue( "region" ) ); entity.setLazyPropertiesCacheable( !"non-lazy".equals( subnode.attributeValue( "include" ) ) ); } } // Primary key constraint entity.createPrimaryKey(); createClassProperties( node, entity, mappings, inheritedMetas ); }
这个类,我还没完全看懂,众所周知,hibernate的配置相当繁多复杂。我就常常记不住,有一次面试的时候,面试官问我hibernate的父类子类继承关系怎么配置,我记不得,所以也说不清。。。 给他留下不好印象。启动,先说到这里。有时间再仔细看看。
总之,configure之后,hibernate的配置就生效,可以使用了!
比如,通过配置获取可使用的 SessionFactory :
factory = cfg.buildSessionFactory();// 获取 factory 是hibernate 许多框架发挥巨大作用的最基础!
等等。
当然,我们一般不用直接通过,Configuration的静态方法configure来启动hibernate。在web应用中,我们通过web容器的相关配置来启动。
比如,在和struts集成(没有spring)的时候,我们通常写一个类似HibernateUtil负责从配置文件中获取、关闭SessionFactory :
public class HibernateUtils { private static SessionFactory factory; static { try { Configuration cfg = new Configuration().configure(); factory = cfg.buildSessionFactory(); }catch(Exception e) { e.printStackTrace(); } } public static SessionFactory getSessionFactory() { return factory; } public static Session getSession() { return factory.openSession(); } public static void closeSession(Session session) { if (session != null) { if (session.isOpen()) { session.close(); } } } }
当然,这其实还是要
Configuration cfg = new Configuration().configure();
factory = cfg.buildSessionFactory();
但由于他是静态初始化块的,所以配置只会被读取一次。当然,session还是要每次来获取的:
factory.openSession(),(是否每次打开同一个session根据情况需要)
factory还提供了api来获取不同的session:
openSession()
openSession(Connection connection)
openSession(Interceptor interceptor)
getCurrentSession()
openStatelessSession()
openStatelessSession(Connection connection)
另外,我们可以通过其他方式启动hibernate,插件方式:
先
import org.apache.struts.action.PlugIn; import org.apache.struts.action.ActionServlet; import org.apache.struts.config.ModuleConfig; import javax.servlet.ServletException; import javax.servlet.ServletContext; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernatePlugIn implements PlugIn { public void destroy() { } public void init(ActionServlet servlet, ModuleConfig config) throws ServletException { try { ServletContext context = servlet.getServletContext(); SessionFactory sf = new Configuration().configure() .buildSessionFactory(); context.setAttribute("org.hibernate.SessionFactory", sf); } catch (Exception ex) { ex.printStackTrace(); } } }
然后在struts-config.xml配置插件信息:
<plug-in className="homepage.HibernatePlugIn"> <set-property property="configFilePath" value="/WEB-INF/classes/hibernate.cfg.xml" /> <set-property property="storeInServletContext" value="true" />
</plug-in>
然后利用java.naming.Context,java.naming.InitiaContext来查找
Context ct = new InitialContext();
sessions=(SessionFactory) ct.lookup("hibernate/session_factory");
session=sessions.openSession();
然后再封装成类似HibernateUtil的类,然后就可以在action中使用了。
如果集成在spring中,我们通常有如下的配置:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
从而通过org.springframework.orm.hibernate3.LocalSessionFactoryBean读取hibernate配置,进而在必要的时候使用hibernateapi,可以说,它这个包装是很有用的。
spring提供有用的HibernateDaoSupport类,简化业务中对数据库的交互:
我们在业务中(通常是dao层)只要继承HibernateDaoSupport,然后再在spring对齐做相应的配置,就可以直接使用HibernateDaoSupport提供的getHibernateTemplate()来获取所需的hibernate session相关方法了,如
save、load、query、update、delete等
推荐阅读
-
基于spring+hibernate+JQuery开发之电子相册(附源码下载)
-
PHP网页游戏学习之Xnova(ogame)源码解读(十三)
-
PHP网页游戏学习之Xnova(ogame)源码解读(十五)
-
PHP网页游戏学习之Xnova(ogame)源码解读(十六)
-
PHP网页游戏学习之Xnova(ogame)源码解读(十四)
-
Android热修复Tinker接入及源码解读
-
PHP网页游戏学习之Xnova(ogame)源码解读(七)
-
PHP网页游戏学习之Xnova(ogame)源码解读(九)
-
PHP网页游戏学习之Xnova(ogame)源码解读(四)
-
PHP网页游戏学习之Xnova(ogame)源码解读(五)