今天在论坛上看到一位朋友希望自己在java中动态的创建hibernate的配置文件(并不是生成而是创建hibernate配置文件对象),脑海中第一个想到的就是spring源码,因为spring有整合hibernate的功能,于是翻阅了spring的代码一看,果然很简单。下面先发断简单的demo。
public
static
void
main(String[] args)
throws
Exception {
Configuration configuration = new Configuration();
Properties properties = new Properties();
properties.setProperty( " hibernate.dialect " ,
" org.hibernate.dialect.SQLServerDialect " );
String[] mappingResources = new String[ 1 ];
mappingResources[ 0 ] = " com/syj/domain/Issue.hbm.xml " ;
for ( int i = 0 ; i < mappingResources.length; i ++ ) {
Resource resource = new ClassPathResource(mappingResources[i]
.trim(), Thread.currentThread().getContextClassLoader());
configuration.addInputStream(resource.getInputStream());
}
configuration.addProperties(properties);
configuration.buildSessionFactory();
}
Configuration configuration = new Configuration();
Properties properties = new Properties();
properties.setProperty( " hibernate.dialect " ,
" org.hibernate.dialect.SQLServerDialect " );
String[] mappingResources = new String[ 1 ];
mappingResources[ 0 ] = " com/syj/domain/Issue.hbm.xml " ;
for ( int i = 0 ; i < mappingResources.length; i ++ ) {
Resource resource = new ClassPathResource(mappingResources[i]
.trim(), Thread.currentThread().getContextClassLoader());
configuration.addInputStream(resource.getInputStream());
}
configuration.addProperties(properties);
configuration.buildSessionFactory();
}
上面代码中properties还缺少很多属性,因为只是个demo所以我没有填写全部的属性,其实这里的属性就是指hibernate.cfg.xml中那些属性,例如hibernate.connection.provider_class,show_sql等等。添加到properties中就可以了。
为什么想到spring的源码呢,下面来看spring中如何整合的
<
bean
id
="sessionFactory"
class ="org.springframework.orm.hibernate3.LocalSessionFactoryBean" >
< property name ="dataSource" >
< ref bean ="dataSource" />
</ property >
< property name ="hibernateProperties" >
< props >
< prop key ="hibernate.dialect" > org.hibernate.dialect.SQLServerDialect </ prop >
< prop key ="hibernate.show_sql" > false </ prop >
< prop key ="hibernate.format_sql" > false </ prop >
< prop key ="hibernate.use_sql_comments" > false </ prop >
<!-- 为单向关联(一对一, 多对一)的外连接抓取(outer join fetch)树设置最大深度. 值为0意味着将关闭默认的外连接抓取 -->
< prop key ="hibernate.max_fetch_depth" > 3 </ prop >
<!-- 为Hibernate关联的批量抓取设置默认数量 -->
< prop key ="hibernate.default_batch_fetch_size" > 8 </ prop >
<!-- 强制Hibernate按照被更新数据的主键,为SQL更新排序。这么做将减少在高并发系统中事务的死锁。 -->
< prop key ="hibernate.order_updates" > true </ prop >
<!-- session在事务完成后将被自动清洗(flush) -->
< prop key ="hibernate.transaction.flush_before_completion" > true </ prop >
<!-- Oracle限制那些通过JDBC驱动传输的字节数组的数目. 如果你希望使用二进值 (binary)或 可序列化的 (serializable)类型的大对象, 你应该开启 hibernate.jdbc.use_streams_for_binary属性. -->
< prop key ="hibernate.bytecode.use_reflection_optimizer" > true </ prop >
</ props >
</ property >
< property name ="mappingResources" >
< list >
< value > com/xxx/domain/xxx.hbm.xml </ value >
</ list >
</ property >
</ bean >
class ="org.springframework.orm.hibernate3.LocalSessionFactoryBean" >
< property name ="dataSource" >
< ref bean ="dataSource" />
</ property >
< property name ="hibernateProperties" >
< props >
< prop key ="hibernate.dialect" > org.hibernate.dialect.SQLServerDialect </ prop >
< prop key ="hibernate.show_sql" > false </ prop >
< prop key ="hibernate.format_sql" > false </ prop >
< prop key ="hibernate.use_sql_comments" > false </ prop >
<!-- 为单向关联(一对一, 多对一)的外连接抓取(outer join fetch)树设置最大深度. 值为0意味着将关闭默认的外连接抓取 -->
< prop key ="hibernate.max_fetch_depth" > 3 </ prop >
<!-- 为Hibernate关联的批量抓取设置默认数量 -->
< prop key ="hibernate.default_batch_fetch_size" > 8 </ prop >
<!-- 强制Hibernate按照被更新数据的主键,为SQL更新排序。这么做将减少在高并发系统中事务的死锁。 -->
< prop key ="hibernate.order_updates" > true </ prop >
<!-- session在事务完成后将被自动清洗(flush) -->
< prop key ="hibernate.transaction.flush_before_completion" > true </ prop >
<!-- Oracle限制那些通过JDBC驱动传输的字节数组的数目. 如果你希望使用二进值 (binary)或 可序列化的 (serializable)类型的大对象, 你应该开启 hibernate.jdbc.use_streams_for_binary属性. -->
< prop key ="hibernate.bytecode.use_reflection_optimizer" > true </ prop >
</ props >
</ property >
< property name ="mappingResources" >
< list >
< value > com/xxx/domain/xxx.hbm.xml </ value >
</ list >
</ property >
</ bean >
大家都知道spring的依赖注入,其实依赖注入很简单这里不做此介绍,我们按照spring的注入流程思考就可以了,下面看看spring优雅的实现把。在这里我们只关注LocalSessionFactoryBean的一个方法:
protected
SessionFactory buildSessionFactory()
throws
Exception {
// Create Configuration instance.
Configuration config = newConfiguration();
DataSource dataSource = getDataSource();
if (dataSource != null ) {
// Make given DataSource available for SessionFactory configuration.
configTimeDataSourceHolder.set(dataSource);
}
if ( this .jtaTransactionManager != null ) {
// Make Spring-provided JTA TransactionManager available.
configTimeTransactionManagerHolder.set( this .jtaTransactionManager);
}
if ( this .lobHandler != null ) {
// Make given LobHandler available for SessionFactory configuration.
// Do early because because mapping resource might refer to custom types.
configTimeLobHandlerHolder.set( this .lobHandler);
}
// Analogous to Hibernate EntityManager's Ejb3Configuration:
// Hibernate doesn't allow setting the bean ClassLoader explicitly,
// so we need to expose it as thread context ClassLoader accordingly.
Thread currentThread = Thread.currentThread();
ClassLoader threadContextClassLoader = currentThread.getContextClassLoader();
boolean overrideClassLoader =
( this .beanClassLoader != null && ! this .beanClassLoader.equals(threadContextClassLoader));
if (overrideClassLoader) {
currentThread.setContextClassLoader( this .beanClassLoader);
}
try {
if ( this .jtaTransactionManager != null ) {
// Set Spring-provided JTA TransactionManager as Hibernate property.
config.setProperty(
Environment.TRANSACTION_MANAGER_STRATEGY, LocalTransactionManagerLookup. class .getName());
config.setProperty(
Environment.TRANSACTION_STRATEGY, JTATransactionFactory. class .getName());
}
else {
// Set connection release mode "on_close" as default.
// This was the case for Hibernate 3.0; Hibernate 3.1 changed
// it to "auto" (i.e. "after_statement" or "after_transaction").
// However, for Spring's resource management (in particular for
// HibernateTransactionManager), "on_close" is the better default.
config.setProperty(Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.ON_CLOSE.toString());
}
if (isExposeTransactionAwareSessionFactory()) {
// Set Hibernate 3.1 CurrentSessionContext implementation,
// providing the Spring-managed Session as current Session.
// Can be overridden by a custom value for the corresponding Hibernate property.
config.setProperty(Environment.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext. class .getName());
}
if ( this .entityInterceptor != null ) {
// Set given entity interceptor at SessionFactory level.
config.setInterceptor( this .entityInterceptor);
}
if ( this .namingStrategy != null ) {
// Pass given naming strategy to Hibernate Configuration.
config.setNamingStrategy( this .namingStrategy);
}
if ( this .typeDefinitions != null ) {
// Register specified Hibernate type definitions.
Mappings mappings = config.createMappings();
for ( int i = 0 ; i < this .typeDefinitions.length; i ++ ) {
TypeDefinitionBean typeDef = this .typeDefinitions[i];
mappings.addTypeDef(typeDef.getTypeName(), typeDef.getTypeClass(), typeDef.getParameters());
}
}
if ( this .filterDefinitions != null ) {
// Register specified Hibernate FilterDefinitions.
for ( int i = 0 ; i < this .filterDefinitions.length; i ++ ) {
config.addFilterDefinition( this .filterDefinitions[i]);
}
}
if ( this .configLocations != null ) {
for ( int i = 0 ; i < this .configLocations.length; i ++ ) {
// Load Hibernate configuration from given location.
config.configure( this .configLocations[i].getURL());
}
}
if ( this .hibernateProperties != null ) {
// Add given Hibernate properties to Configuration.
config.addProperties( this .hibernateProperties);
}
if (dataSource != null ) {
boolean actuallyTransactionAware =
(isUseTransactionAwareDataSource() || dataSource instanceof TransactionAwareDataSourceProxy);
// Set Spring-provided DataSource as Hibernate ConnectionProvider.
config.setProperty(Environment.CONNECTION_PROVIDER,
actuallyTransactionAware ?
TransactionAwareDataSourceConnectionProvider. class .getName() :
LocalDataSourceConnectionProvider. class .getName());
}
if ( this .mappingResources != null ) {
// Register given Hibernate mapping definitions, contained in resource files.
for ( int i = 0 ; i < this .mappingResources.length; i ++ ) {
Resource resource = new ClassPathResource( this .mappingResources[i].trim(), this .beanClassLoader);
config.addInputStream(resource.getInputStream());
}
}
if ( this .mappingLocations != null ) {
// Register given Hibernate mapping definitions, contained in resource files.
for ( int i = 0 ; i < this .mappingLocations.length; i ++ ) {
config.addInputStream( this .mappingLocations[i].getInputStream());
}
}
if ( this .cacheableMappingLocations != null ) {
// Register given cacheable Hibernate mapping definitions, read from the file system.
for ( int i = 0 ; i < this .cacheableMappingLocations.length; i ++ ) {
config.addCacheableFile( this .cacheableMappingLocations[i].getFile());
}
}
if ( this .mappingJarLocations != null ) {
// Register given Hibernate mapping definitions, contained in jar files.
for ( int i = 0 ; i < this .mappingJarLocations.length; i ++ ) {
Resource resource = this .mappingJarLocations[i];
config.addJar(resource.getFile());
}
}
if ( this .mappingDirectoryLocations != null ) {
// Register all Hibernate mapping definitions in the given directories.
for ( int i = 0 ; i < this .mappingDirectoryLocations.length; i ++ ) {
File file = this .mappingDirectoryLocations[i].getFile();
if ( ! file.isDirectory()) {
throw new IllegalArgumentException(
" Mapping directory location [ " + this .mappingDirectoryLocations[i] +
" ] does not denote a directory " );
}
config.addDirectory(file);
}
}
if ( this .entityCacheStrategies != null ) {
// Register cache strategies for mapped entities.
for (Enumeration classNames = this .entityCacheStrategies.propertyNames(); classNames.hasMoreElements();) {
String className = (String) classNames.nextElement();
String[] strategyAndRegion =
StringUtils.commaDelimitedListToStringArray( this .entityCacheStrategies.getProperty(className));
if (strategyAndRegion.length > 1 ) {
config.setCacheConcurrencyStrategy(className, strategyAndRegion[ 0 ], strategyAndRegion[ 1 ]);
}
else if (strategyAndRegion.length > 0 ) {
config.setCacheConcurrencyStrategy(className, strategyAndRegion[ 0 ]);
}
}
}
if ( this .collectionCacheStrategies != null ) {
// Register cache strategies for mapped collections.
for (Enumeration collRoles = this .collectionCacheStrategies.propertyNames(); collRoles.hasMoreElements();) {
String collRole = (String) collRoles.nextElement();
String[] strategyAndRegion =
StringUtils.commaDelimitedListToStringArray( this .collectionCacheStrategies.getProperty(collRole));
if (strategyAndRegion.length > 1 ) {
config.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[ 0 ], strategyAndRegion[ 1 ]);
}
else if (strategyAndRegion.length > 0 ) {
config.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[ 0 ]);
}
}
}
if ( this .eventListeners != null ) {
// Register specified Hibernate event listeners.
for (Iterator it = this .eventListeners.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
Assert.isTrue(entry.getKey() instanceof String, " Event listener key needs to be of type String " );
String listenerType = (String) entry.getKey();
Object listenerObject = entry.getValue();
if (listenerObject instanceof Collection) {
Collection listeners = (Collection) listenerObject;
EventListeners listenerRegistry = config.getEventListeners();
Object[] listenerArray =
(Object[]) Array.newInstance(listenerRegistry.getListenerClassFor(listenerType), listeners.size());
listenerArray = listeners.toArray(listenerArray);
config.setListeners(listenerType, listenerArray);
}
else {
config.setListener(listenerType, listenerObject);
}
}
}
// Perform custom post-processing in subclasses.
postProcessConfiguration(config);
// Build SessionFactory instance.
logger.info( " Building new Hibernate SessionFactory " );
this .configuration = config;
return newSessionFactory(config);
}
finally {
if (dataSource != null ) {
// Reset DataSource holder.
configTimeDataSourceHolder.set( null );
}
if ( this .jtaTransactionManager != null ) {
// Reset TransactionManager holder.
configTimeTransactionManagerHolder.set( null );
}
if ( this .lobHandler != null ) {
// Reset LobHandler holder.
configTimeLobHandlerHolder.set( null );
}
if (overrideClassLoader) {
// Reset original thread context ClassLoader.
currentThread.setContextClassLoader(threadContextClassLoader);
}
}
}
// Create Configuration instance.
Configuration config = newConfiguration();
DataSource dataSource = getDataSource();
if (dataSource != null ) {
// Make given DataSource available for SessionFactory configuration.
configTimeDataSourceHolder.set(dataSource);
}
if ( this .jtaTransactionManager != null ) {
// Make Spring-provided JTA TransactionManager available.
configTimeTransactionManagerHolder.set( this .jtaTransactionManager);
}
if ( this .lobHandler != null ) {
// Make given LobHandler available for SessionFactory configuration.
// Do early because because mapping resource might refer to custom types.
configTimeLobHandlerHolder.set( this .lobHandler);
}
// Analogous to Hibernate EntityManager's Ejb3Configuration:
// Hibernate doesn't allow setting the bean ClassLoader explicitly,
// so we need to expose it as thread context ClassLoader accordingly.
Thread currentThread = Thread.currentThread();
ClassLoader threadContextClassLoader = currentThread.getContextClassLoader();
boolean overrideClassLoader =
( this .beanClassLoader != null && ! this .beanClassLoader.equals(threadContextClassLoader));
if (overrideClassLoader) {
currentThread.setContextClassLoader( this .beanClassLoader);
}
try {
if ( this .jtaTransactionManager != null ) {
// Set Spring-provided JTA TransactionManager as Hibernate property.
config.setProperty(
Environment.TRANSACTION_MANAGER_STRATEGY, LocalTransactionManagerLookup. class .getName());
config.setProperty(
Environment.TRANSACTION_STRATEGY, JTATransactionFactory. class .getName());
}
else {
// Set connection release mode "on_close" as default.
// This was the case for Hibernate 3.0; Hibernate 3.1 changed
// it to "auto" (i.e. "after_statement" or "after_transaction").
// However, for Spring's resource management (in particular for
// HibernateTransactionManager), "on_close" is the better default.
config.setProperty(Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.ON_CLOSE.toString());
}
if (isExposeTransactionAwareSessionFactory()) {
// Set Hibernate 3.1 CurrentSessionContext implementation,
// providing the Spring-managed Session as current Session.
// Can be overridden by a custom value for the corresponding Hibernate property.
config.setProperty(Environment.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext. class .getName());
}
if ( this .entityInterceptor != null ) {
// Set given entity interceptor at SessionFactory level.
config.setInterceptor( this .entityInterceptor);
}
if ( this .namingStrategy != null ) {
// Pass given naming strategy to Hibernate Configuration.
config.setNamingStrategy( this .namingStrategy);
}
if ( this .typeDefinitions != null ) {
// Register specified Hibernate type definitions.
Mappings mappings = config.createMappings();
for ( int i = 0 ; i < this .typeDefinitions.length; i ++ ) {
TypeDefinitionBean typeDef = this .typeDefinitions[i];
mappings.addTypeDef(typeDef.getTypeName(), typeDef.getTypeClass(), typeDef.getParameters());
}
}
if ( this .filterDefinitions != null ) {
// Register specified Hibernate FilterDefinitions.
for ( int i = 0 ; i < this .filterDefinitions.length; i ++ ) {
config.addFilterDefinition( this .filterDefinitions[i]);
}
}
if ( this .configLocations != null ) {
for ( int i = 0 ; i < this .configLocations.length; i ++ ) {
// Load Hibernate configuration from given location.
config.configure( this .configLocations[i].getURL());
}
}
if ( this .hibernateProperties != null ) {
// Add given Hibernate properties to Configuration.
config.addProperties( this .hibernateProperties);
}
if (dataSource != null ) {
boolean actuallyTransactionAware =
(isUseTransactionAwareDataSource() || dataSource instanceof TransactionAwareDataSourceProxy);
// Set Spring-provided DataSource as Hibernate ConnectionProvider.
config.setProperty(Environment.CONNECTION_PROVIDER,
actuallyTransactionAware ?
TransactionAwareDataSourceConnectionProvider. class .getName() :
LocalDataSourceConnectionProvider. class .getName());
}
if ( this .mappingResources != null ) {
// Register given Hibernate mapping definitions, contained in resource files.
for ( int i = 0 ; i < this .mappingResources.length; i ++ ) {
Resource resource = new ClassPathResource( this .mappingResources[i].trim(), this .beanClassLoader);
config.addInputStream(resource.getInputStream());
}
}
if ( this .mappingLocations != null ) {
// Register given Hibernate mapping definitions, contained in resource files.
for ( int i = 0 ; i < this .mappingLocations.length; i ++ ) {
config.addInputStream( this .mappingLocations[i].getInputStream());
}
}
if ( this .cacheableMappingLocations != null ) {
// Register given cacheable Hibernate mapping definitions, read from the file system.
for ( int i = 0 ; i < this .cacheableMappingLocations.length; i ++ ) {
config.addCacheableFile( this .cacheableMappingLocations[i].getFile());
}
}
if ( this .mappingJarLocations != null ) {
// Register given Hibernate mapping definitions, contained in jar files.
for ( int i = 0 ; i < this .mappingJarLocations.length; i ++ ) {
Resource resource = this .mappingJarLocations[i];
config.addJar(resource.getFile());
}
}
if ( this .mappingDirectoryLocations != null ) {
// Register all Hibernate mapping definitions in the given directories.
for ( int i = 0 ; i < this .mappingDirectoryLocations.length; i ++ ) {
File file = this .mappingDirectoryLocations[i].getFile();
if ( ! file.isDirectory()) {
throw new IllegalArgumentException(
" Mapping directory location [ " + this .mappingDirectoryLocations[i] +
" ] does not denote a directory " );
}
config.addDirectory(file);
}
}
if ( this .entityCacheStrategies != null ) {
// Register cache strategies for mapped entities.
for (Enumeration classNames = this .entityCacheStrategies.propertyNames(); classNames.hasMoreElements();) {
String className = (String) classNames.nextElement();
String[] strategyAndRegion =
StringUtils.commaDelimitedListToStringArray( this .entityCacheStrategies.getProperty(className));
if (strategyAndRegion.length > 1 ) {
config.setCacheConcurrencyStrategy(className, strategyAndRegion[ 0 ], strategyAndRegion[ 1 ]);
}
else if (strategyAndRegion.length > 0 ) {
config.setCacheConcurrencyStrategy(className, strategyAndRegion[ 0 ]);
}
}
}
if ( this .collectionCacheStrategies != null ) {
// Register cache strategies for mapped collections.
for (Enumeration collRoles = this .collectionCacheStrategies.propertyNames(); collRoles.hasMoreElements();) {
String collRole = (String) collRoles.nextElement();
String[] strategyAndRegion =
StringUtils.commaDelimitedListToStringArray( this .collectionCacheStrategies.getProperty(collRole));
if (strategyAndRegion.length > 1 ) {
config.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[ 0 ], strategyAndRegion[ 1 ]);
}
else if (strategyAndRegion.length > 0 ) {
config.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[ 0 ]);
}
}
}
if ( this .eventListeners != null ) {
// Register specified Hibernate event listeners.
for (Iterator it = this .eventListeners.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
Assert.isTrue(entry.getKey() instanceof String, " Event listener key needs to be of type String " );
String listenerType = (String) entry.getKey();
Object listenerObject = entry.getValue();
if (listenerObject instanceof Collection) {
Collection listeners = (Collection) listenerObject;
EventListeners listenerRegistry = config.getEventListeners();
Object[] listenerArray =
(Object[]) Array.newInstance(listenerRegistry.getListenerClassFor(listenerType), listeners.size());
listenerArray = listeners.toArray(listenerArray);
config.setListeners(listenerType, listenerArray);
}
else {
config.setListener(listenerType, listenerObject);
}
}
}
// Perform custom post-processing in subclasses.
postProcessConfiguration(config);
// Build SessionFactory instance.
logger.info( " Building new Hibernate SessionFactory " );
this .configuration = config;
return newSessionFactory(config);
}
finally {
if (dataSource != null ) {
// Reset DataSource holder.
configTimeDataSourceHolder.set( null );
}
if ( this .jtaTransactionManager != null ) {
// Reset TransactionManager holder.
configTimeTransactionManagerHolder.set( null );
}
if ( this .lobHandler != null ) {
// Reset LobHandler holder.
configTimeLobHandlerHolder.set( null );
}
if (overrideClassLoader) {
// Reset original thread context ClassLoader.
currentThread.setContextClassLoader(threadContextClassLoader);
}
}
}