Hibernate源码分析

先扯二句蛋:做Java也有很久了,安卓也搞了半年,回想自己当初学习java,j2ee的时候,全靠自己,没有老师,没有同学,书籍就是老师,搜索引擎就是同学,磕磕绊绊下来,终于有所心得,从今天开始准备好好的写一些博客,希望能帮助到那些刚上路,或者在路上却有些迷茫的童鞋```` 
最近有在研究hibernate这个框架的源码,所以这一阶段会将自己的研究进度和心得用简单的方式贴出来,希望帮到大家的同时,大家也能指出其中的问题,一起讨论,共同进步!(注意:这是源码分析,需要对hibernate有一定了解,起码使用过,所以没有使用过hibernate的童鞋还是先去使用使用在来看吧,不然只能一头雾水`````) 
那么就从头开始,且听我细细道来: 
hibernate大家都用过,使用下面这个东西大家应该都很熟悉 
Configuration cfg = new Configuration().configure(); 

SessionFactory factory = cfg.buildSessionFactory(); 
这样就获取到了我们Dao层中所需要的SessionFactory了 

那么configure()这个方法中做了什么?上源码 
public Configuration configure() throws HibernateException { 
  configure( "/hibernate.cfg.xml" ); 
  return this; 

看,这里就是去加载解析/hibernate.cfg.xml去了,显然是用configure(String resource)方法,这个方法做了什么?上源码 
public Configuration configure(String resource) throws HibernateException { 
  LOG.configuringFromResource( resource ); //打了个日志 
  InputStream stream = getConfigurationInputStream( resource ); //获取这个xml文件的输入流 
  return doConfigure( stream, resource );//用这个输入流去生成orm映射的对象了! 


那doConfigure( stream, resource )做了什么?上源码 
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 ) );//这里就用这个输入流去生成一个Document 对象了,很显然,hibernate使用了SAX解析 
   if ( errorLogger.hasErrors() ) { 
    throw new MappingException( "invalid configuration", errorLogger.getErrors().get( 0 ) ); 
   } 
   doConfigure( document );//看,再一次调用了重载的 doConfigure( Document  document )方法 
  } 
  catch (DocumentException e) { 
   throw new HibernateException( "Could not parse configuration: " + resourceName, e ); 
  } 
  finally { 
   try { 
    stream.close(); 
   } 
   catch (IOException ioe) { 
    LOG.unableToCloseInputStreamForResource( resourceName, ioe ); 
   } 
  } 
  return this; 


那么重载的 doConfigure( Document  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 ); 
  } 
  LOG.configuredSessionFactory( name ); 
  LOG.debugf( "Properties: %s", properties ); 
  return this; 

很显然,这个方法处理了两个节点:session-factory和security 
session-factory这个节点很是熟悉啊,自然是用来指明各个映射文件的 
security节点再议 
parseSessionFactory( sfNode, name );就是去利用这个节点去找到各个映射文件,然后做映射,完成orm 
那他做了啥?上源码 
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 ); 
   } 
  } 


这里处理了3个节点mapping,class-cache,collection-cache,mapping节点很是熟悉啊,这就是咱为每个domain对象做的映射文件啊,其他两再议 
处理mapping节点时调用了parseMappingElement( subelement, name );,那他做了啥?上源码 
private void parseMappingElement(Element mappingElement, String name) { 
  final Attribute resourceAttribute = mappingElement.attribute( "resource" ); 
  final Attribute fileAttribute = mappingElement.attribute( "file" ); 
  final Attribute jarAttribute = mappingElement.attribute( "jar" ); 
  final Attribute packageAttribute = mappingElement.attribute( "package" ); 
  final Attribute classAttribute = mappingElement.attribute( "class" ); 
  if ( resourceAttribute != null ) { 
   final String resourceName = resourceAttribute.getValue(); 
   LOG.debugf( "Session-factory config [%s] named resource [%s] for mapping", name, resourceName ); 
   addResource( resourceName ); 
  } 
  else if ( fileAttribute != null ) { 
   final String fileName = fileAttribute.getValue(); 
   LOG.debugf( "Session-factory config [%s] named file [%s] for mapping", name, fileName ); 
   addFile( fileName ); 
  } 
  else if ( jarAttribute != null ) { 
   final String jarFileName = jarAttribute.getValue(); 
   LOG.debugf( "Session-factory config [%s] named jar file [%s] for mapping", name, jarFileName ); 
   addJar( new File( jarFileName ) ); 
  } 
  else if ( packageAttribute != null ) { 
   final String packageName = packageAttribute.getValue(); 
   LOG.debugf( "Session-factory config [%s] named package [%s] for mapping", name, packageName ); 
   addPackage( packageName ); 
  } 
  else if ( classAttribute != null ) { 
   final String className = classAttribute.getValue(); 
   LOG.debugf( "Session-factory config [%s] named class [%s] for mapping", name, className ); 
   try { 
    addAnnotatedClass( ReflectHelper.classForName( className ) ); 
   } 
   catch ( Exception e ) { 
    throw new MappingException( 
      "Unable to load class [ " + className + "] declared in Hibernate configuration <mapping/> entry", 
      e 
    ); 
   } 
  } 
  else { 
   throw new MappingException( "<mapping> element in configuration specifies no known attributes" ); 
  } 

很长,本着解决主要矛盾,忽略次要矛盾的马列哲学思想,我们还是来关注我们最熟悉的,用class来配置,也就是上面的 
else if ( classAttribute != null ) { 
   final String className = classAttribute.getValue(); 
   LOG.debugf( "Session-factory config [%s] named class [%s] for mapping", name, className ); 
   try { 
    addAnnotatedClass( ReflectHelper.classForName( className ) ); 
   } 
   catch ( Exception e ) { 
    throw new MappingException( 
      "Unable to load class [ " + className + "] declared in Hibernate configuration <mapping/> entry", 
      e 
    ); 
   } 
两个LOG.debugf输出的文字很熟悉吧,就是hibernate启动时常常看见的,控制台打出的日志 
那么 addAnnotatedClass( ReflectHelper.classForName( className ) );就是正式进入解析阶段了,且看具体做了什么, 
首先不着急,我们看看ReflectHelper.classForName(className ),从名字就可以看出来用了反射技术去从className这个名字反射出一个类出来,暂时把他当做一个黑箱好了,只要知道传入一个对的名字就可以得到一个正确的Class类就ok了。 
在得到类后传入看看做了啥: 
@SuppressWarnings({ "unchecked" }) 
public Configuration addAnnotatedClass(Class annotatedClass) { 
  XClass xClass = reflectionManager.toXClass( annotatedClass ); 
  metadataSourceQueue.add( xClass ); 
  return this; 

言简意赅,用了一个ReflectionManager对象的toXClass将我们的Class变成了Hibernate自定义的XClass,然后在metadataSourceQueue这个队列中加入了这个XClass,然后一个个映射就出炉了!以后我们就直接使用内存中的队列metadataSourceQueue就ok了 
整个解析过程就是这个样子,看Hibernate源码果真是一种享受,很通俗易懂,言简意赅,不想某些公司的项目代码,简直一团乱麻! 
ok,不抱怨了,且看几个细节问题,XClass究竟为何物,为何要将Class转化为XClass,MetadataSourceQueue又是何物? 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值