`
bsr1983
  • 浏览: 1101264 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Hibernate源码学习四 _服务注册

 
阅读更多

接学习三中的内容,首先看一下如何根据配置文件创建一个SessionFactory,通过跟踪相关代码来了解其中的来龙去脉。

      主方法中创建SessionFactory相关的代码为:

         

ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
            .applySettings(configuration.getProperties())
            .buildServiceRegistry();
      //根据所注册的服务创建sessionFactory
      SessionFactory sessionFactory = configuration
           .buildSessionFactory(serviceRegistry);

 

其中,首先要获取Configuration中的属性。那么这个属性是如何获取的呢?

通过查看Configuration的源码,我们知道在调用protected Configuration doConfigure(Document doc) throws HibernateException方法的时候,在其内部调用了addProperties( sfNode );代码如下:

private void addProperties(Element parent) {
      Iterator itr = parent.elementIterator( "property" );
      while ( itr.hasNext() ) {
         Element node = (Element) itr.next();
         String name = node.attributeValue( "name" );
         String value = node.getText().trim();
         LOG.debugf( "%s=%s", name, value );
         properties.setProperty( name, value );
         if ( !name.startsWith( "hibernate" ) ) {
            properties.setProperty( "hibernate." + name, value );
         }
      }
      Environment.verifyProperties( properties );
  }

 

  这里通过获取根节点下的所有property元素来获取对应的属性。通过获取property元素的name属性和对应的值来设置属性,如果该属性不是以hibernate开头的,那么就默认给属性添加一个hibernate.的前缀。最后一步是Environment.verifyProperties( properties );

具体的代码如下:

public static void verifyProperties(Map<?,?> configurationValues) {
      final Map propertiesToAdd = new HashMap();
      for ( Map.Entry entry : configurationValues.entrySet() ) {
         final Object replacementKey = OBSOLETE_PROPERTIES.get( entry.getKey() );
         if ( replacementKey != null ) {
            LOG.unsupportedProperty( entry.getKey(), replacementKey );
         }
         final Object renamedKey = RENAMED_PROPERTIES.get( entry.getKey() );
         if ( renamedKey != null ) {
            LOG.renamedProperty( entry.getKey(), renamedKey );
            propertiesToAdd.put( renamedKey, entry.getValue() );
         }
      }
      configurationValues.putAll( propertiesToAdd );
  }

 

此处的校验主要是去除一些已废弃的属性和需要进行重命名的属性,应该是为了兼容性考虑,将之前用过的一些已废弃的属性名称转换为当前版本中正确的属性名称,调试发现OBSOLETE_PROPERTIESRENAMED_PROPERTIES为无元素的Map,其声明的代码为:

private static final Map OBSOLETE_PROPERTIES = new HashMap();
private static final Map RENAMED_PROPERTIES = new HashMap();

 

声明为静态私有的不可变的Map,且并为给该Map添加元素可以证明之前的推测此处仅是为了兼容性考虑的推断是正确的。

  再看

public final class Environment implements AvailableSettings

 ,这个类是实现了AvailableSettings接口的类,而AvailableSettings接口中声明了大量的属性名,看到很多都是我们在hibernate.cfg.xml中配置过,或者是在hibernate.properties文件中使用的key名称。包括hibernate.connection.driver_classhibernate.connection.urlhibernate.connection.username等等。

  通过Debug来查看configuration.getProperties()的值,具体值见下图



 

可以看到这个Map中包含了95个元素,其中的与hibernate配置相关的属性的key并未以hibernate开头,而是和我们在hibernate.cfg.xml中配置的key名称是一致的,我们可以修改一下我们的配置文件,改成标准的属性名称,在调试到此处,看看值有没有变化。

这次我将hibernate.cfg.xml修改为如下代码:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernatecode</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">root</property>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <mapping resource="com/ibsrapp/hibernatecode/domain/UserInfo.hbm.xml" />
    </session-factory>
</hibernate-configuration>

 

此时再通过Debug来查看configuration.getProperties()的值,具体值见下图:

  

 

此时的key和我们配置文件中的一致,都加上了hibernate的前缀。也就是可以得出一个结论,在我们的配置文件中可以省略hibernate.这个前缀,hibernate在校验其标准属性的时候会自动为增加前缀,以便通过校验,如果我们增加一些未定义的属性名称,则会将该属性忽略。如果进行Debug可以看到,在当前的HashMap并没有包含自定义的那些属性。

  但具体定义这些规定配置属性的属性名称的类是

org.hibernate.cfg.AvailableSettings,在该类中定义了配置项中的属性名称,可以看到,这里的属性名称都是包含“hibernate.”前缀的。具体的使用就是通过定义的静态字符串,从属性的Map中获取对应的值。例如在org.hibernate.cfg.SettingsFactory类中的方法buildSettings,代码如下:

public Settings buildSettings(Properties props, ServiceRegistry serviceRegistry) {
      final boolean debugEnabled =  LOG.isDebugEnabled();
      final JdbcServices jdbcServices = serviceRegistry.getService( JdbcServices.class );
      Settings settings = new Settings();
 
      //SessionFactory name:
 
      String sessionFactoryName = props.getProperty( AvailableSettings.SESSION_FACTORY_NAME );
      settings.setSessionFactoryName( sessionFactoryName );
      settings.setSessionFactoryNameAlsoJndiName(
            ConfigurationHelper.getBoolean( AvailableSettings.SESSION_FACTORY_NAME_IS_JNDI, props, true )
      );

 

以下代码略,中的String sessionFactoryName = props.getProperty( AvailableSettings.SESSION_FACTORY_NAME );

这里就使用了定义的静态变量AvailableSettings.SESSION_FACTORY_NAME作为key,其实际值为“hibernate.session_factory_name”。

  从上述截图中可以看到,这个属性map中还包含了很多系统属性。

  具体初始化的部分是在Environment的一个静态语句块中进行的初始化,除了获取系统属性,同时还会设置一些其他的全局设定代码如下:

   

static {
		Version.logVersion();
		//初始化事务级别静态常量与对应的字符串值的Map
		Map<Integer,String> temp = new HashMap<Integer,String>();
		temp.put( Connection.TRANSACTION_NONE, "NONE" );
		temp.put( Connection.TRANSACTION_READ_UNCOMMITTED, "READ_UNCOMMITTED" );
		temp.put( Connection.TRANSACTION_READ_COMMITTED, "READ_COMMITTED" );
		temp.put( Connection.TRANSACTION_REPEATABLE_READ, "REPEATABLE_READ" );
		temp.put( Connection.TRANSACTION_SERIALIZABLE, "SERIALIZABLE" );
		ISOLATION_LEVELS = Collections.unmodifiableMap( temp );
		GLOBAL_PROPERTIES = new Properties();
		//Set USE_REFLECTION_OPTIMIZER to false to fix HHH-227
		GLOBAL_PROPERTIES.setProperty( USE_REFLECTION_OPTIMIZER, Boolean.FALSE.toString() );
//读取hibernate.properties属性文件,获取全局属性
		try {
			InputStream stream = ConfigHelper.getResourceAsStream( "/hibernate.properties" );
			try {
				GLOBAL_PROPERTIES.load(stream);
				LOG.propertiesLoaded( ConfigurationHelper.maskOut( GLOBAL_PROPERTIES, PASS ) );
			}
			catch (Exception e) {
				LOG.unableToLoadProperties();
			}
			finally {
				try{
					stream.close();
				}
				catch (IOException ioe){
					LOG.unableToCloseStreamError( ioe );
				}
			}
		}
		catch (HibernateException he) {
			LOG.propertiesNotFound();
		}
		//获取当前系统属性,也放入到全局属性中
		try {
		    Properties systemProperties = System.getProperties();
		    // Must be thread-safe in case an application changes System properties during Hibernate initialization.
		    // See HHH-8383.
		    synchronized (systemProperties) {
		    	GLOBAL_PROPERTIES.putAll(systemProperties);
		    }
		} catch (SecurityException se) {
		    LOG.unableToCopySystemProperties();
		}
//校验全局属性,具体的代码参见上文
		verifyProperties(GLOBAL_PROPERTIES);

		ENABLE_BINARY_STREAMS = ConfigurationHelper.getBoolean(USE_STREAMS_FOR_BINARY, GLOBAL_PROPERTIES);
		if ( ENABLE_BINARY_STREAMS ) {
			LOG.usingStreams();
		}

		ENABLE_REFLECTION_OPTIMIZER = ConfigurationHelper.getBoolean(USE_REFLECTION_OPTIMIZER, GLOBAL_PROPERTIES);
		if ( ENABLE_REFLECTION_OPTIMIZER ) {
			LOG.usingReflectionOptimizer();
		}

		BYTECODE_PROVIDER_INSTANCE = buildBytecodeProvider( GLOBAL_PROPERTIES );
//校验当前的jvm是否存在timestamp的bug
		long x = 123456789;
		JVM_HAS_TIMESTAMP_BUG = new Timestamp(x).getTime() != x;
		if ( JVM_HAS_TIMESTAMP_BUG ) {
			LOG.usingTimestampWorkaround();
		}
	}

 

       

  注册服务服务部分代码分析:

  主类中代码:

ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
            . applySettings (configuration.getProperties())
           .buildServiceRegistry();

 

      下面看看ServiceRegistryBuilder类中相关的代码都做了哪些操作:

  首先是new ServiceRegistryBuilder(),用来调用无参构造函数创建一个ServiceRegistryBuilder对象。看一下对应的方法内容:

  

 public ServiceRegistryBuilder() {
      this( new BootstrapServiceRegistryImpl() );
  }

 

其实是调用了另一个构造方法,从Environment获取当前的全局设定属性,并将上一个构造函数中传递的BootstrapServiceRegistry实现类对象设置为当前的引导服务注册变量:

  

 public ServiceRegistryBuilder(BootstrapServiceRegistry bootstrapServiceRegistry) {
      this.settings = Environment.getProperties();
      this.bootstrapServiceRegistry = bootstrapServiceRegistry;
  }

 

BootstrapServiceRegistryImpl的定义如下

public class BootstrapServiceRegistryImpl
     implements ServiceRegistryImplementor, BootstrapServiceRegistry, ServiceBinding.ServiceLifecycleOwner

 

可以看到其实现了3个不同的接口,但都和服务注册和绑定有关,而其构造函数在初始化的时候会初始化其所拥有的两个与类加载和拦截器有关的服务,具体参见其源码。

applySettings方法的代码如下,其实就是将configuration中配置的数据添加到当前的settingMap中。

public ServiceRegistryBuilder applySettings(Map settings) {
      this.settings.putAll( settings );
      return this;
  }

 

接下来看一下buildServiceRegistry

public ServiceRegistry buildServiceRegistry() {
       Map<?,?> settingsCopy = new HashMap();
       settingsCopy.putAll( settings );
       Environment.verifyProperties( settingsCopy );
       //处理以${系统属性名}为value的属性,即将其value设置为具体的属性值,如//果指定的属性不存在,置为””
       ConfigurationHelper.resolvePlaceHolders( settingsCopy );
//貌似在处理拦截器服务的顺序,感觉和struts的拦截器类似,暂未深入研究
       for ( Integrator integrator : bootstrapServiceRegistry.getService( IntegratorService.class ).getIntegrators() ) {
           if ( ServiceContributingIntegrator.class.isInstance( integrator ) ) {
              ServiceContributingIntegrator.class.cast( integrator ).prepareServices( this );
           }
       }
//调用本地另一个构造方法创建一个实例对象返回
       return new StandardServiceRegistryImpl( bootstrapServiceRegistry, initiators, providedServices, settingsCopy );
  }

 

调用的构造方法如下,主要还是进行了服务的绑定:

public StandardServiceRegistryImpl(
         BootstrapServiceRegistry bootstrapServiceRegistry,
         List<BasicServiceInitiator> serviceInitiators,
         List<ProvidedService> providedServices,
         Map<?, ?> configurationValues) {
      super( bootstrapServiceRegistry );
 
      this.configurationValues = configurationValues;
 
      // process initiators
      for ( ServiceInitiator initiator : serviceInitiators ) {
         createServiceBinding( initiator );
      }
 
      // then, explicitly provided service instances
      for ( ProvidedService providedService : providedServices ) {
         createServiceBinding( providedService );
      }
  }

 

  • 大小: 30.9 KB
  • 大小: 27 KB
0
2
分享到:
评论
4 楼 bsr1983 2013-09-22  
zh_harry 写道
bsr1983 写道
zh_harry 写道
还有人把hibernate学得这么起劲想不明白

知识储备不足,深入学习下,不知您有啥建议,学点别的?

用的不多了解,ORM看看mybatis吧,或者自己写一个,hibernate有点重,不适合大型项目。

谢谢您的建议,完了看下mybatis
3 楼 zh_harry 2013-09-22  
bsr1983 写道
zh_harry 写道
还有人把hibernate学得这么起劲想不明白

知识储备不足,深入学习下,不知您有啥建议,学点别的?

用的不多了解,ORM看看mybatis吧,或者自己写一个,hibernate有点重,不适合大型项目。
2 楼 bsr1983 2013-09-22  
zh_harry 写道
还有人把hibernate学得这么起劲想不明白

知识储备不足,深入学习下,不知您有啥建议,学点别的?
1 楼 zh_harry 2013-09-12  
还有人把hibernate学得这么起劲想不明白

相关推荐

    Struts2.1+Sptring+Hibernate注册系统的源码

    这是一个基于Struts2.1+Sptring+Hibernate的完整的注册系统。用于爱好者学习使用,请勿用作商品。

    简单的struts2和hibernate框架注册逻辑 SimpleStruts2Hibernate.rar

    简单的struts2和hibernate框架注册逻辑 源码描述: 一、源码介绍 整合struts2和hibernate框架,实现简单的注册逻辑,会判断新注册用户的账户是否存在,存在不允许注册。 二、注意事项 1、开发环境为Visual Studio...

    java_jsp项目源码_博客系统(struts+hibernate+spring).rar

    本项目是一个基于Struts、Hibernate和Spring框架的Java JSP博客系统,旨在提供一个功能...本博客系统源码完整,注释清晰,适合Java Web开发者学习和二次开发定制,可广泛应用于个人博客、企业官网、在线杂志等场景。

    Struts2+Spring3+Hibernate3 用户管理系统实例源码

    本例主要是实现了struts2+spring3+hibernate3的 基本框架搭建的注册登录,以及用户增删改查,适于初学者学习。 包括:注册 登录功能 分页的实现 前端校验 验证码的实现 注册时有ajax 校验,登录时 后台从数据库...

    java_jsp项目源码_通用的在线考试系统(+struts+hibernate+oracle).rar

    通用的在线考试系统是一个基于Java、JSP、Struts、Hibernate和Oracle数据库的综合性考试解决方案。它为教育机构、企业和个人提供了一个高效、灵活且可扩展的在线考试平台。该系统具有以下主要功能: 1. 用户管理:...

    java_jsp项目源码_通用的在线考试系统(+struts+hibernate+oracle)130220.rar

    通用的在线考试系统是一个基于Java、JSP、Struts、Hibernate和Oracle数据库的综合性考试解决方案。它为教育机构、企业和个人提供了一个高效、灵活且可扩展的在线考试平台。该系统具有以下主要功能: 1. 用户管理:...

    源码基于JSP的网上书店(struts+hibernate+css+mysql).rar

    这是一个基于JSP的网上书店项目的源码资料包,该项目采用了Struts框架和Hibernate技术进行开发,同时使用了CSS样式表进行页面美化,数据库方面则选择了MySQL作为数据存储方案。这个资料包包含了完整的源代码,可以...

    源码基于JSP的图书管理系统(struts+hibernate+spring+ext).rar

    这是一个基于JSP的图书管理系统的源码资料包,它采用了Struts、Hibernate、Spring和Ext等技术进行开发。这个系统的主要功能包括图书的增删改查、用户的注册登录、借阅归还等操作。通过这个源码资料包,你可以了解到...

    博客系统(struts+hibernate+spring).rar

    博客系统(struts+hibernate+spring).rar是一个计算机专业JSP源码资料包,它包含了一个完整的博客系统。这个博客系统使用了Struts、Hibernate和Spring这三个流行的Java框架来实现。Struts是一个用于创建Java Web应用...

    JAVA上百实例源码以及开源项目源代码

    Java 源码包 Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来...

    开源bbs源码java-MyChatRoom:基于struts2、hibernate和ajax

    开源 bbs 源码 ...Struts2和Hibernate的学习,《Java web开发实战》 Ajax和Jquery的部分知识, Bootstrap框架, 背景图片来源, 部分配置问题参考, normalize.css来源, 部分前端设计参考思科论坛,

    java源码包---java 源码 大量 实例

    Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行ATM...

    java源码包3

    Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行...

    Technicolor BBS 留言板系统(Struts+Spring+Hibernate)

    此留言板系统是在下学习中的一个练习程序,功能比较简单,初学者有兴趣可以参考一下(在下也是初学者~) 实现的功能: 1、注册登陆 2、留言 3、查看留言 4、评论 5、管理员,包括删除修改 系统实现: 1、...

    java源码包2

    Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行...

    java源码包4

    Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行...

    JAVA上百实例源码以及开源项目

    笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级、中级、高级等,详情看源码列表,需要的可以直接下载! 这些源码反映了那时那景笔者对未来的盲目,对代码的热情、执着,对IT的憧憬、向往!此时此...

    java版当当网登陆注册验证源码

    主要功能是在线浏览图书信息,订购图书,管理图书。技术实现:struts、hibernate、javascript、css、mysql等,主要提供学习所用。

    基于struts+hibernate的网上订餐系统设计与实现

    用户模块:主要实现注册个人信息和修改个人信息、登录、查看商品、购物车和订单信息。管理员模块:主要实现修改密码、用户信息管理、商品类别管理、商品信息管理、订单管理。 采用B/S架构更加便于访问,并且使用SSH...

    【毕业设计】SSH框架实战项目——在线商品拍卖网(源码+数据库).zip

    这个项目属于学习Java Web的SSH框架的练习之作,参考至《Struts2+Spring+Hibernate框架技术与项目实战》这本书的第24章。 一 介绍 (1)开发环境: eclipse for javaee + JDK1.8x + tomcat1.8 + MySQL5.x (2)...

Global site tag (gtag.js) - Google Analytics