diff --git a/spring-orm-hibernate5/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java b/spring-orm-hibernate5/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java index b4d2d941ab..aef0311f75 100644 --- a/spring-orm-hibernate5/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java +++ b/spring-orm-hibernate5/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBean.java @@ -23,8 +23,10 @@ import javax.sql.DataSource; import org.hibernate.Interceptor; import org.hibernate.SessionFactory; +import org.hibernate.boot.MetadataSources; import org.hibernate.boot.model.naming.ImplicitNamingStrategy; import org.hibernate.boot.model.naming.PhysicalNamingStrategy; +import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.context.spi.CurrentTenantIdentifierResolver; @@ -40,6 +42,7 @@ import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternUtils; import org.springframework.core.task.AsyncTaskExecutor; import org.springframework.core.type.filter.TypeFilter; +import org.springframework.util.Assert; /** * {@link FactoryBean} that creates a Hibernate @@ -96,7 +99,9 @@ public class LocalSessionFactoryBean extends HibernateExceptionTranslator private AsyncTaskExecutor bootstrapExecutor; - private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); + private MetadataSources metadataSources; + + private ResourcePatternResolver resourcePatternResolver; private Configuration configuration; @@ -318,15 +323,58 @@ public class LocalSessionFactoryBean extends HibernateExceptionTranslator this.bootstrapExecutor = bootstrapExecutor; } + /** + * Specify a Hibernate {@link MetadataSources} service to use (e.g. reusing an + * existing one), potentially populated with a custom Hibernate bootstrap + * {@link org.hibernate.service.ServiceRegistry} as well. + * @since 4.3 + */ + public void setMetadataSources(MetadataSources metadataSources) { + Assert.notNull(metadataSources, "MetadataSources must not be null"); + this.metadataSources = metadataSources; + } + + /** + * Determine the Hibernate {@link MetadataSources} to use. + *

Can also be externally called to initialize and pre-populate a {@link MetadataSources} + * instance which is then going to be used for {@link SessionFactory} building. + * @return the MetadataSources to use (never {@code null}) + * @since 4.3 + * @see LocalSessionFactoryBuilder#LocalSessionFactoryBuilder(DataSource, ResourceLoader, MetadataSources) + */ + public MetadataSources getMetadataSources() { + if (this.metadataSources == null) { + this.metadataSources = new MetadataSources(new BootstrapServiceRegistryBuilder().build()); + } + return this.metadataSources; + } + + /** + * Specify a Spring {@link ResourceLoader} to use for Hibernate metadata. + * @param resourceLoader the ResourceLoader to use (never {@code null}) + */ @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader); } + /** + * Determine the Spring {@link ResourceLoader} to use for Hibernate metadata. + * @return the ResourceLoader to use (never {@code null}) + * @since 4.3 + */ + public ResourceLoader getResourceLoader() { + if (this.resourcePatternResolver == null) { + this.resourcePatternResolver = new PathMatchingResourcePatternResolver(); + } + return this.resourcePatternResolver; + } + @Override public void afterPropertiesSet() throws IOException { - LocalSessionFactoryBuilder sfb = new LocalSessionFactoryBuilder(this.dataSource, this.resourcePatternResolver); + LocalSessionFactoryBuilder sfb = new LocalSessionFactoryBuilder( + this.dataSource, getResourceLoader(), getMetadataSources()); if (this.configLocations != null) { for (Resource resource : this.configLocations) { diff --git a/spring-orm-hibernate5/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java b/spring-orm-hibernate5/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java index 6fe88b8bff..f49b2f283d 100644 --- a/spring-orm-hibernate5/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java +++ b/spring-orm-hibernate5/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java @@ -38,6 +38,8 @@ import javax.transaction.TransactionManager; import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.SessionFactory; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; @@ -116,6 +118,20 @@ public class LocalSessionFactoryBuilder extends Configuration { * @param resourceLoader the ResourceLoader to load application classes from */ public LocalSessionFactoryBuilder(DataSource dataSource, ResourceLoader resourceLoader) { + this(dataSource, resourceLoader, new MetadataSources(new BootstrapServiceRegistryBuilder().build())); + } + + /** + * Create a new LocalSessionFactoryBuilder for the given DataSource. + * @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using + * (may be {@code null}) + * @param resourceLoader the ResourceLoader to load application classes from + * @param metadataSources the Hibernate MetadataSources service to use (e.g. reusing an existing one) + * @since 4.3 + */ + public LocalSessionFactoryBuilder(DataSource dataSource, ResourceLoader resourceLoader, MetadataSources metadataSources) { + super(metadataSources); + getProperties().put(Environment.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext.class.getName()); if (dataSource != null) { getProperties().put(Environment.DATASOURCE, dataSource); @@ -298,6 +314,7 @@ public class LocalSessionFactoryBuilder extends Configuration { /** * Proxy invocation handler for background bootstrapping, only enforcing * a fully initialized target {@code SessionFactory} when actually needed. + * @since 4.3 */ private class BootstrapSessionFactoryInvocationHandler implements InvocationHandler {