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 );
      }
  }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值