论坛首页 Java企业应用论坛

New Configuration().add(parent.class)背后发生的故事!

浏览 8445 次
该帖已经被评为精华帖
作者 正文
   发表时间:2004-05-22  
这篇文章只是关心hibernate关于Binder部分的技术细节,对其他部分没有太多涉及。另:写这篇文章只是给大家一个摸索hibernate背后运作的大概线索,并不是一份准确详细的技术说明文档,如果有错误之处,请大家指正!!

Hibernate中,将对象分为两类:value type和entity type.关于这一点的详细说明,大家可以参考hibernate的refenrence。我这里只说明一点entity就是我们要操作的必须持久化的对象,一个entity 至少对应一张表(多张表的存在源于集合的引入)。而值类型有可能对应于某张表的1个或多个字段(参见component定义),hibernate为之专门定义了一个SimpleValue来Mapping.
对于一个需要持久化的对象类parent(这里为了简单起见,用父子关系中的parent来讨论)。
import java.util.*;

/**
 * @author Administrator
 *
 * To change the template for this generated type comment go to
 * Window&Preferences&Java&Code Generation&Code and Comments
 */
public class Parent {
	private int id;
	private String name;
	private Set children;
	protected Map holidays;
	public Map getHolidays(){
		return holidays;
	}
	public void setHolidays(Map hols){
		this.holidays=hols;
	}
	public int getId(){
		return id;
	}
	public void setId(int id){
		this.id=id;
	}
	public Parent(){
		children=new HashSet();
	}
	public String getName(){
		return name;
	}
	public void setName(String name){
		this.name=name;
	}
	public Set getChildren(){
		return children;
	}
	public void setChildren(Set children){
		this.children=children;
	}
	public void addChild(Child c) {
		c.setParent(this);
		children.add(c);
	}


}

add(***.class)以后得所有步骤涉及最主要得类:Configuration,Binder,Mappings,RootClass,。
大家可以看一下它们的源文件,我简要说明如下:
Configuration:
private Map classes = new HashMap();
private Map imports = new HashMap();
private Map collections = new HashMap();
private Map tables = new HashMap();
private Map namedQueries = new HashMap();
private Map namedSqlQueries = new HashMap();
private List secondPasses = new ArrayList();
private List propertyReferences = new ArrayList();
private Interceptor interceptor = EMPTY_INTERCEPTOR;
private Properties properties = Environment.getProperties();
private Map caches = new HashMap();
private NamingStrategy namingStrategy = DefaultNamingStrategy.INSTANCE; 
private static Log log = LogFactory.getLog(Configuration.class);

classes将会被用来保存对应于entity类的映射类,在这个例子中,add(Parent.class)后,classes的key 为Parent.class,对应的value为net.sf.hibernate.mapping.RootClass for class Parent.class.
值的说明的是net.sf.hibernate.mapping.RootClass这个类。涉及它的继承体系为
PersisitentClass
|
|

|                          |
RootClass          SubClass

RootClass便是我们xml文件中对应于<class>元素定义的对象,而SubClass对应于<Subclass>节点对应的对象。
(接上Configuration)Collections用来保留所有用到的集合类,如在这个例子中,add(Parent.class)后,,collections中将有两项数据:
1)key(“org.hibernate.auction.Parent.children”)—value(net.sf.hibernate.mapping.Set实例for children);
2)key(“org.hibernate.auction.Parent.holidays”)---value(net.sf.hibernate.mapping.Map实例for holidays).

Tables用来保存App中所有net.sf.hibernate.mapping.Table 实例,key为tableName(注意这里的net.sf.hibernate.mapping.Table实例是真正映射数据库中的一张表,一一对应。如上面的Parent.class会生成两个Table实例,对应”parent”和”holidays”)
SecondPasses:因为collection的引入使得持久类之间有了关联关系,为了绑定并且保存对应于每一个collection而建立的net.sf.hibernate.mapping.集合类 与持久类之间,以及持久类与持久类之间的关联,hibernate使用了一个SecondPass内部类。每一个collection对应建立一个SecondPass实例。SecondPasses为以后cascade操作提供了重要信息。
Properties:保存JVM 重要环境信息以及在hibernate.properties中设定的重要属性,包括jNDI,数据库方言等等。这些信息在进行session.save等操作时,提供重要信息。

NamingStrategy用来定义从className映射到TableName等等这样的名字映射策略。

Mappings:
import net.sf.hibernate.mapping.Table;

/**
 * A collection of mappings from classes and collections to
 * relational database tables. (Represents a single
 * <tt>&hibernate-mapping&</tt> element.)
 * @author Gavin King
 */
public class Mappings {
	
	private static final Log log = LogFactory.getLog(Mappings.class);
	
	private final Map classes;
	private final Map collections;
	private final Map tables;
	private final Map queries;
	private final Map sqlqueries;
	private final List secondPasses;
	private final Map imports;
	private String schemaName;
	private String defaultCascade;
	private String defaultPackage;
	private String defaultAccess;
	private boolean autoImport;
	private final List propertyReferences;
	private final Map caches;
	private final NamingStrategy namingStrategy;

Gavin的话:A collection of mappings from classes and collections to
relational database tables. (Represents a single hibernate-mapping&gt element.已经说明了这个类的重要作用。
至于PersistentClass和RootClass,这是很重要的类,里面封装了持久entity的所有信息,源码也不是很复杂,大家可以看一下。重要信息如下:
private Class mappedClass;
	private String discriminatorValue;
	private Map properties = new SequencedHashMap();
	private Table table;
	private Class proxyInterface;
	private final ArrayList subclasses = new ArrayList();
	private final ArrayList subclassProperties = new ArrayList();
	private final ArrayList subclassTables = new ArrayList();
	private boolean dynamicInsert;
	private boolean dynamicUpdate;
	private int batchSize=1;
	private boolean selectBeforeUpdate;
	private int optimisticLockMode;
	private java.util.Map metaAttributes;

值的说明的是:mappedClass便是我们要映射的entity类(Parent.class),大家看一下dtd中对于<class>节点的属性表,便可知道针对于<class>元素的属性都要相应设置RootClass的属性。



add(parent.class)促发步骤(一些我认为没必要说明的步骤略去):
1) 在Confugurations中。用classloader装载parent.class,
2) 由类名parent.class映射出hbm文件parent.class-àparent.hbm.xml
3) 用sax解析器读取parent.hbm.xml形成一个Document内存对象。(分支1:如果不是一个well-form文件则抛出异常)
4) 调用Binder.bindRoot(org.dom4j.Document doc,Mappings createMappings() )(值得说明的是createMappings(),这个方法位于Configuration类中,返回 封装了所有Configuation的重要集合成员的Mappings.
5) 现在指挥权到了Binder类中,bindRoot传进来的参数是一个document和封装了Configuration所有重要成员的mappings。
6) 在Binder.bindRoot中,我简要罗列以下步骤:
         a) Element hmNode = doc.getRootElement();(取出xml文档中的跟节点,也就是<hibernate-mapping>节点。建议大家结合看dtd定义文件,了解每个元素的属性,因为所有这些属性hibernate都要一一取出,然后设置相应model的属性,任何一个属性都是对后发操作有着深远得影响。)
         b) 根据<hibernate-mapping〉节点各个属性设置mappings的属性。
         c) Iterator nodes = hmNode.elementIterator("class");(这里要遍历XML文件中定义的所有<class>元素,他们的每一个都是一个rootClass。)
         d) 进入对<class>元素的循环遍历。
               d-1) Element n = (Element) nodes.next();
                      d-2) RootClass rootclass = new RootClass();
                      d-3) Binder.bindRootClass(n, rootclass, mappings);

                             bindRootClass(Element node, RootClass model,   Mappings mappings)是Binder类得核心方法,顾名思义,就是对<class>元素的Bind动作,这个bind包括对<class>元素属性的bind,还包括class元素所含所有得子元素的bind,因为篇幅所限,其具体方法动作我会在以后文档中给出详细说明。我这里简要概括一下方法步骤:
                    d-3-1)Binder.bindClass(Element node, PersistentClass model, Mappings mapping) 。bindClass方法是仅仅对<class>节点本身以及一些属性的绑定动作,并不包括<class〉子元素的绑定,而且关心的属性也不是全部。主要根据<class>元素的”name”属性找出entity class,然后调用RootClass.setMappedClass(parent.calss);接下来就是根据class元素的其中一些属性设置初始化rootclass。
                    d-3-2)
 Attribute schemaNode = node.attribute("schema");
String schema = schemaNode==null ? mappings.getSchemaName() : schemaNode.getValue();
Table table = mappings.addTable( schema, getClassTableName(model, node, mappings) );
model.setTable(table);

这里主要根据属性生成Table实例,注意这里的net.sf.hibernate.mapping.Table实例仅仅设置了tableName 和schema而已,别的属性并没有初始化。需要在下面的步骤中进行更多的设置。
        d-3-3)根据<class>元素的剩余属性对rootClass进行设置。


                   d-3-4)对<class>的所有子元素进行遍历,在这个循环遍历中,hibernate仅仅注意这样跟初始化RootClass有重要影响的子元素及元素的所有属性( (cache|jcs-cache),(id|composite-id),discriminator, (version|timestamp)),hibernate必须根据这些重要元素的设置对RootClass以及Mappings进行bind。
                   d-3-5)
 		model.createPrimaryKey();

在这一步,根据d-3-4)中对<id>节点生成的Identifier,设置PrimaryKey。
                   d-3-6)
 propertiesFromXML(node, model, mappings);

Binder. propertiesFromXML(Element node, PersistentClass model, Mappings mappings)也是一个重要方法。我觉得有必要深究一下。详细文档我也会在以后文档中给出。参阅源码,大家可以看出它的逻辑是相当清晰的。就是对<set><Map><property><many-to-one>等等子元素进行bind。
e) 进入对< subclass><joined-subclass>< query>< sql-query>等等的遍历处理。
f) 。。。。
g) 返回。
   发表时间:2004-05-22  
我是初学者,刚开始看到.add(*.class)时,想看一下源代码,无赖自己hibernate
及综合素质太差,没看出个所以然,今天楼主却给写出来了!谢谢楼主!
不过我现在仍然似懂非懂,文章收藏先!等一段时间后再来研究。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics