zoukankan      html  css  js  c++  java
  • Hibernate 5.x 生成 SessionFactory 源码跟踪分析

    我们要使用 Hibernate 的功能,首先需要读取 Hibernate 的配置文件,根据配置启动 Hibernate ,然后创建 SessionFactory。

    创建 SessionFactory 的代码很简单,这也是我们要分析的代码:

    Configuration cfg = new Configuration().configure();
    SessionFactory factory = cfg.buildSessionFactory();
    

    接下来,就针对这两行代码进行分析。

    1、初始化 Configuration

    首先,我们来看看初始化 Configuration 实例的源码中都做了些什么:

    public Configuration() {
    	this( new BootstrapServiceRegistryBuilder().build() );
    }
    

    无参构造器调用了重载的构造器,接着看重载的构造器,Configuration.class 第121行:

    public Configuration(BootstrapServiceRegistry serviceRegistry) {
    	this.bootstrapServiceRegistry = serviceRegistry;
    	this.metadataSources = new MetadataSources( serviceRegistry );
    	reset();
    }
    

    在这个构造器中,有个reset() 方法我们等下再看。我们先来看看传入的参数 serviceRegistry,以及初始化的两个成员属性:

    • BootstrapServiceRegistry 是个接口,翻译过来是“启动服务注册器”,是 Hibernate 底层的的基础服务注册器。
    • MetadataSources 元数据来源,构造器接收了 BootstrapServiceRegistry 的实例

    看一下这个构造器的源码,MeatadataSources.class 第 77 行:

    // 使用指定的服务注册器实例创建一个 Metadata “元数据的源”
    public MetadataSources(ServiceRegistry serviceRegistry) {
    
    	// 传入的参数还只能是 BootstrapServiceRegistry 或 StandardServiceRegistry 类型的实例
    	if ( ! isExpectedServiceRegistryType( serviceRegistry ) ) {
    		LOG.debugf(
    				"Unexpected ServiceRegistry type [%s] encountered during building of MetadataSources; may cause " +
    						"problems later attempting to construct MetadataBuilder",
    				serviceRegistry.getClass().getName()
    		);
    	}
    	this.serviceRegistry = serviceRegistry;
    	this.xmlMappingBinderAccess = new XmlMappingBinderAccess( serviceRegistry );
    }
    

    好像看不太明白,那我们来看看这个 MetadataSource 类的说明注释:

    Entry point into working with sources of metadata information (mapping XML, annotations). Tell Hibernate about sources and then call buildMetadata() , or use getMetadataBuilder() to customize how sources are processed (naming strategies, etc).

    加载元数据信息(一般是XML文件、注解中配置的映射)。Hibernate 加载该信息之后,通过调用 buildMetadata() 或者 getMetadataBuilder() 方法来确定整个 Hibernate 运行时环境的执行策略。

    看到这里,可以认为 MetadataSource 的就是用来加载配置信息的。其实在 Metadata 中,就存储了 ORM 的映射信息。

    构造方法的最后一行代码:

    this.xmlMappingBinderAccess = new XmlMappingBinderAccess( serviceRegistry );
    

    我们继续跟踪看看 XmlMappingBinderAccess 的构造方法做了些什么:

    public XmlMappingBinderAccess(ServiceRegistry serviceRegistry) {
    	this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
    
    	// NOTE : 参数中的 boolean 值表示在加载 XML 文件时是否执行验证。
    	// 在这里显式指定为true,可以让运行时的 JAXP(XML处理的Java API)和 JAXB(根据XML生成Java类)启动速度更快,
    	// 如果不验证 XML,可能会因为 XML 中的一些小错误而导致大麻烦。
    	this.mappingBinder 
    		= new MappingBinder( serviceRegistry.getService( ClassLoaderService.class ), true );
    }
    

    好了,我们现在知道这行代码是在做 XML 文件中绑定映射初始化相关的处理


    继续回到 Configuration(BootstrapServiceRegistry serviceRegistry) 重载构造器中。

    先简单说明一下 Hibernate 中的 Service:

    BootstrapServiceRegistry 接口的父接口是 ServiceRegistry,这个接口的父接口是 Service
    Hibernate 将所有的底层的功能都封装为 Service 注册到 ServiceRegistry 中,需要的时候通过 getService() 方法获取即可。

    刚刚留下了一行 reset() 方法没有看,我们现在来看看,Configuration.class 第 149 行:

    protected void reset() {
    	implicitNamingStrategy = ImplicitNamingStrategyJpaCompliantImpl.INSTANCE;
    	physicalNamingStrategy = PhysicalNamingStrategyStandardImpl.INSTANCE;
    	namedQueries = new HashMap<String,NamedQueryDefinition>();
    	namedSqlQueries = new HashMap<String,NamedSQLQueryDefinition>();
    	sqlResultSetMappings = new HashMap<String, ResultSetMappingDefinition>();
    	namedEntityGraphMap = new HashMap<String, NamedEntityGraphDefinition>();
    	namedProcedureCallMap = new HashMap<String, NamedProcedureCallDefinition>(  );
    
    	// 初始化 standardServiceRegistryBuilder 成员变量
    	standardServiceRegistryBuilder = new StandardServiceRegistryBuilder( bootstrapServiceRegistry );
    	entityTuplizerFactory = new EntityTuplizerFactory();
    	interceptor = EmptyInterceptor.INSTANCE;
    	properties = new Properties(  );
    	properties.putAll( standardServiceRegistryBuilder.getSettings());
    }
    

    implicitNamingStrategyphysicalNamingStrategy 就是 Hibernate 的命名策略相关的实例:

    • implicitNamingStrategy:隐式命名策略
    • physicalNamingStrategy:物理命名策略

    命名策略有多种实现方式:Hibernate 标准,JPA 标准。可以调用 Configuration 对象的 setImplicitNamingStrategy()setPhysicalNamingStrategy() 方法设置命名策略。

    扩展:Hibernate中实体映射时的命名策略

    引用一张图片,显示了 Hibernate 5.x 中的命名策略的关系:

    Hibernate 5.X 命名策略关系

    在这里先不对命名策略做太细化的研究,我们接着看下面几行代码中的 HashMap 实例分别代表什么:

    • namedQuerys 读取映射文件中<query>元素的内容或注解,该元素用于定义 HQL 语句
    • namedSqlQueries 读取映射文件中<sql-query>元素的内容或注解,该元素用于定义 SQL 语句
    • sqlResultSetMappings 读取映射文件中 SQL 查询结果集的结构内容。
    • namedEntityGraphMap 读取映射文件或注解中的 EntityGraph 配置,是 JPA 2.1 的新规范
    • namedProcedureCallMap 存储过程相关的配置

    我对 reset() 方法小结一下:重置初始化了另一些成员变量(囧)

    至此,Configuration 的初始化过程就已经完成了。


    接着调用 Configuration 对象的 configure() 方法,可以重载该方法指定配置文件的资源路径。

    我们先来看看无参的方法:

    // 在程序的资源路径下,读取文件名为 hibernate.cfg.xml 映射配置文件
    public Configuration configure() throws HibernateException {
    	return configure( StandardServiceRegistryBuilder.DEFAULT_CFG_RESOURCE_NAME );
    }
    

    再来看看有参的方法:

    // 读取符合 hibernate-configuration-3.0.dtd 文档类型规范的配置文件
    public Configuration configure(String resource) throws HibernateException {
    	standardServiceRegistryBuilder.configure( resource );
    	// ...
    	properties.putAll( standardServiceRegistryBuilder.getSettings() );
    	return this;
    }
    

    我们可以发现, configure() 方法内部调用了 standardServiceRegistryBuilder.configure( resource );,如果我们只是使用 Configuration 对象,那么这个方法就没有作用,这里我们还是追踪了看一下,追踪到类 StandardServiceRegistryBuilder,看看其中的 configure() 做了什么处理:

    // 从指定的资源位置,读取 XML 文件获取配置信息(常用)
    public StandardServiceRegistryBuilder configure(String resourceName) {
    	return configure( configLoader.loadConfigXmlResource( resourceName ) );
    }
    
    // 指定 File 对象
    public StandardServiceRegistryBuilder configure(File configurationFile) {
    	return configure( configLoader.loadConfigXmlFile( configurationFile ) );
    }
    
    // 可以获取网络上的指定路径URL
    public StandardServiceRegistryBuilder configure(URL url) {
    	return configure( configLoader.loadConfigXmlUrl( url ) );
    }
    
    // 有多个 cfg.xml 文件时,合并它们
    public StandardServiceRegistryBuilder configure(LoadedConfig loadedConfig) {
    	aggregatedCfgXml.merge( loadedConfig );
    	settings.putAll( loadedConfig.getConfigurationValues() );
    	return this;
    }
    

    最终返回了 StandardServiceRegistryBuilder 对象,这个对象用作 Hibernate 5.x 中创建 SessionFactory。关于 Hibernate 5.x 的创建方式,将在另一篇文章中讲解。

    2、创建 SessionFactory

    接下来,看我们要分析的第二行代码:

    SessionFactory factory = cfg.buildSessionFactory();
    

    调用 Configuration 对象的 buildSessionFactory() 方法。我们进到这个方法看看里面是什么:

    // 使用当前 configuration 配置对象中的配置信息创建一个 SessionFactory 实例,该实例被创建后就不会再改变
    // 此后再对 configuration 做修改也不会影响到已创建的 SessionFactory 实例
    public SessionFactory buildSessionFactory() throws HibernateException {
    	log.debug( "Building session factory using internal StandardServiceRegistryBuilder" );
    	// ----- 1、使用 properties 重置配置属性 -----
    	standardServiceRegistryBuilder.applySettings( properties );
    	return buildSessionFactory( standardServiceRegistryBuilder.build() );
    }
    
    public SessionFactory buildSessionFactory(ServiceRegistry serviceRegistry) throws HibernateException {
    	log.debug( "Building session factory using provided StandardServiceRegistry" );
    
    	// ----- 2、创建 MetadataBuilder ,然后做一些配置工作 -----
    	final MetadataBuilder metadataBuilder = metadataSources
    		.getMetadataBuilder( (StandardServiceRegistry) serviceRegistry );
    	// 设置默认的隐式命名策略
    	if ( implicitNamingStrategy != null ) {
    		metadataBuilder.applyImplicitNamingStrategy( implicitNamingStrategy );
    	}
    	// 设置默认的物理命名策略
    	if ( physicalNamingStrategy != null ) {
    		metadataBuilder.applyPhysicalNamingStrategy( physicalNamingStrategy );
    	}
    	// 设置共享缓存模式
    	if ( sharedCacheMode != null ) {
    		metadataBuilder.applySharedCacheMode( sharedCacheMode );
    	}
    	if ( !typeContributorRegistrations.isEmpty() ) {
    		for ( TypeContributor typeContributor : typeContributorRegistrations ) {
    			metadataBuilder.applyTypes( typeContributor );
    		}
    	}
    	if ( !basicTypes.isEmpty() ) {
    		for ( BasicType basicType : basicTypes ) {
    			metadataBuilder.applyBasicType( basicType );
    		}
    	}
    	if ( sqlFunctions != null ) {
    		for ( Map.Entry<String, SQLFunction> entry : sqlFunctions.entrySet() ) {
    			metadataBuilder.applySqlFunction( entry.getKey(), entry.getValue() );
    		}
    	}
    	if ( auxiliaryDatabaseObjectList != null ) {
    		for ( AuxiliaryDatabaseObject auxiliaryDatabaseObject : auxiliaryDatabaseObjectList ) {
    			metadataBuilder.applyAuxiliaryDatabaseObject( auxiliaryDatabaseObject );
    		}
    	}
    	if ( attributeConverterDefinitionsByClass != null ) {
    		for ( AttributeConverterDefinition attributeConverterDefinition : attributeConverterDefinitionsByClass.values() ) {
    			metadataBuilder.applyAttributeConverter( attributeConverterDefinition );
    		}
    	}
    
    	// ----- 3、使用 MetadataBuilder 创建 Metadata 实例 -----
    	final Metadata metadata = metadataBuilder.build();
    	
    	// 使用 Metadata 对象的 getSessionFactoryBuilder() 创建 SessionFactoryBuilder
    	final SessionFactoryBuilder sessionFactoryBuilder = 
    		 metadata.getSessionFactoryBuilder();
    	if ( interceptor != null && interceptor != EmptyInterceptor.INSTANCE ) {
    		sessionFactoryBuilder.applyInterceptor( interceptor );
    	}
    	if ( getSessionFactoryObserver() != null ) {
    		// 为 SessionFactory 添加观察者 Observers
    		sessionFactoryBuilder.addSessionFactoryObservers( getSessionFactoryObserver() );
    	}
    	if ( getEntityNotFoundDelegate() != null ) {
    		sessionFactoryBuilder.applyEntityNotFoundDelegate( getEntityNotFoundDelegate() );
    	}
    	if ( getEntityTuplizerFactory() != null ) {
    		sessionFactoryBuilder.applyEntityTuplizerFactory( getEntityTuplizerFactory() );
    	}
    	if ( getCurrentTenantIdentifierResolver() != null ) {
    		sessionFactoryBuilder.applyCurrentTenantIdentifierResolver( getCurrentTenantIdentifierResolver() );
    	}
    	
    	// 4、创建并返回 SessionFactory 实例
    	return sessionFactoryBuilder.build();
    }
    

    buildSessionFactory() 方法的内容比较多,但是主要就是3个核心步骤:

    1. 创建 MetadataBuilder ,然后做一些配置工作
    2. 使用 MetadataBuilder 创建 Metadata 实例,metadata 中存储了所有的 ORM 映射信息
    3. 创建并返回 SessionFactory 实例

    至此,Hibernate 5.x 创建 SessionFactory 的源码全部走完。

  • 相关阅读:
    今日总结
    每日总结
    每日总结
    每日总结
    重返现世
    [PKUWC2018]随机游走
    [HAOI2015]按位或
    [NOI2020] 超现实树
    [NOI2017] 游戏
    [CSACADEMY]Card Groups
  • 原文地址:https://www.cnblogs.com/uzipi/p/8094555.html
Copyright © 2011-2022 走看看