001/* 002 * Copyright 2002-2020 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.orm.hibernate5; 018 019import java.io.File; 020import java.io.IOException; 021import java.util.Properties; 022 023import javax.sql.DataSource; 024 025import org.hibernate.Interceptor; 026import org.hibernate.SessionFactory; 027import org.hibernate.boot.MetadataSources; 028import org.hibernate.boot.model.naming.ImplicitNamingStrategy; 029import org.hibernate.boot.model.naming.PhysicalNamingStrategy; 030import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; 031import org.hibernate.cache.spi.RegionFactory; 032import org.hibernate.cfg.Configuration; 033import org.hibernate.context.spi.CurrentTenantIdentifierResolver; 034import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider; 035import org.hibernate.integrator.spi.Integrator; 036import org.hibernate.service.ServiceRegistry; 037 038import org.springframework.beans.factory.BeanFactory; 039import org.springframework.beans.factory.BeanFactoryAware; 040import org.springframework.beans.factory.DisposableBean; 041import org.springframework.beans.factory.FactoryBean; 042import org.springframework.beans.factory.InitializingBean; 043import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 044import org.springframework.context.ResourceLoaderAware; 045import org.springframework.core.io.ClassPathResource; 046import org.springframework.core.io.Resource; 047import org.springframework.core.io.ResourceLoader; 048import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 049import org.springframework.core.io.support.ResourcePatternResolver; 050import org.springframework.core.io.support.ResourcePatternUtils; 051import org.springframework.core.task.AsyncTaskExecutor; 052import org.springframework.core.type.filter.TypeFilter; 053import org.springframework.lang.Nullable; 054import org.springframework.util.ClassUtils; 055 056/** 057 * {@link FactoryBean} that creates a Hibernate {@link SessionFactory}. This is the usual 058 * way to set up a shared Hibernate SessionFactory in a Spring application context; the 059 * SessionFactory can then be passed to data access objects via dependency injection. 060 * 061 * <p>Compatible with Hibernate 5.0/5.1 as well as 5.2/5.3/5.4, as of Spring 5.2. 062 * Set up with Hibernate 5.2+, {@code LocalSessionFactoryBean} is an immediate alternative 063 * to {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean} for common 064 * JPA purposes: In particular with Hibernate 5.3/5.4, the Hibernate {@code SessionFactory} 065 * will natively expose the JPA {@code EntityManagerFactory} interface as well, and 066 * Hibernate {@code BeanContainer} integration will be registered out of the box. 067 * In combination with {@link HibernateTransactionManager}, this naturally allows for 068 * mixing JPA access code with native Hibernate access code within the same transaction. 069 * 070 * @author Juergen Hoeller 071 * @since 4.2 072 * @see #setDataSource 073 * @see #setPackagesToScan 074 * @see HibernateTransactionManager 075 * @see LocalSessionFactoryBuilder 076 * @see org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean 077 */ 078public class LocalSessionFactoryBean extends HibernateExceptionTranslator 079 implements FactoryBean<SessionFactory>, ResourceLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean { 080 081 @Nullable 082 private DataSource dataSource; 083 084 @Nullable 085 private Resource[] configLocations; 086 087 @Nullable 088 private String[] mappingResources; 089 090 @Nullable 091 private Resource[] mappingLocations; 092 093 @Nullable 094 private Resource[] cacheableMappingLocations; 095 096 @Nullable 097 private Resource[] mappingJarLocations; 098 099 @Nullable 100 private Resource[] mappingDirectoryLocations; 101 102 @Nullable 103 private Interceptor entityInterceptor; 104 105 @Nullable 106 private ImplicitNamingStrategy implicitNamingStrategy; 107 108 @Nullable 109 private PhysicalNamingStrategy physicalNamingStrategy; 110 111 @Nullable 112 private Object jtaTransactionManager; 113 114 @Nullable 115 private RegionFactory cacheRegionFactory; 116 117 @Nullable 118 private MultiTenantConnectionProvider multiTenantConnectionProvider; 119 120 @Nullable 121 private CurrentTenantIdentifierResolver currentTenantIdentifierResolver; 122 123 @Nullable 124 private Properties hibernateProperties; 125 126 @Nullable 127 private TypeFilter[] entityTypeFilters; 128 129 @Nullable 130 private Class<?>[] annotatedClasses; 131 132 @Nullable 133 private String[] annotatedPackages; 134 135 @Nullable 136 private String[] packagesToScan; 137 138 @Nullable 139 private AsyncTaskExecutor bootstrapExecutor; 140 141 @Nullable 142 private Integrator[] hibernateIntegrators; 143 144 private boolean metadataSourcesAccessed = false; 145 146 @Nullable 147 private MetadataSources metadataSources; 148 149 @Nullable 150 private ResourcePatternResolver resourcePatternResolver; 151 152 @Nullable 153 private ConfigurableListableBeanFactory beanFactory; 154 155 @Nullable 156 private Configuration configuration; 157 158 @Nullable 159 private SessionFactory sessionFactory; 160 161 162 /** 163 * Set the DataSource to be used by the SessionFactory. 164 * If set, this will override corresponding settings in Hibernate properties. 165 * <p>If this is set, the Hibernate settings should not define 166 * a connection provider to avoid meaningless double configuration. 167 */ 168 public void setDataSource(DataSource dataSource) { 169 this.dataSource = dataSource; 170 } 171 172 /** 173 * Set the location of a single Hibernate XML config file, for example as 174 * classpath resource "classpath:hibernate.cfg.xml". 175 * <p>Note: Can be omitted when all necessary properties and mapping 176 * resources are specified locally via this bean. 177 * @see Configuration#configure(java.net.URL) 178 */ 179 public void setConfigLocation(Resource configLocation) { 180 this.configLocations = new Resource[] {configLocation}; 181 } 182 183 /** 184 * Set the locations of multiple Hibernate XML config files, for example as 185 * classpath resources "classpath:hibernate.cfg.xml,classpath:extension.cfg.xml". 186 * <p>Note: Can be omitted when all necessary properties and mapping 187 * resources are specified locally via this bean. 188 * @see Configuration#configure(java.net.URL) 189 */ 190 public void setConfigLocations(Resource... configLocations) { 191 this.configLocations = configLocations; 192 } 193 194 /** 195 * Set Hibernate mapping resources to be found in the class path, 196 * like "example.hbm.xml" or "mypackage/example.hbm.xml". 197 * Analogous to mapping entries in a Hibernate XML config file. 198 * Alternative to the more generic setMappingLocations method. 199 * <p>Can be used to add to mappings from a Hibernate XML config file, 200 * or to specify all mappings locally. 201 * @see #setMappingLocations 202 * @see Configuration#addResource 203 */ 204 public void setMappingResources(String... mappingResources) { 205 this.mappingResources = mappingResources; 206 } 207 208 /** 209 * Set locations of Hibernate mapping files, for example as classpath 210 * resource "classpath:example.hbm.xml". Supports any resource location 211 * via Spring's resource abstraction, for example relative paths like 212 * "WEB-INF/mappings/example.hbm.xml" when running in an application context. 213 * <p>Can be used to add to mappings from a Hibernate XML config file, 214 * or to specify all mappings locally. 215 * @see Configuration#addInputStream 216 */ 217 public void setMappingLocations(Resource... mappingLocations) { 218 this.mappingLocations = mappingLocations; 219 } 220 221 /** 222 * Set locations of cacheable Hibernate mapping files, for example as web app 223 * resource "/WEB-INF/mapping/example.hbm.xml". Supports any resource location 224 * via Spring's resource abstraction, as long as the resource can be resolved 225 * in the file system. 226 * <p>Can be used to add to mappings from a Hibernate XML config file, 227 * or to specify all mappings locally. 228 * @see Configuration#addCacheableFile(File) 229 */ 230 public void setCacheableMappingLocations(Resource... cacheableMappingLocations) { 231 this.cacheableMappingLocations = cacheableMappingLocations; 232 } 233 234 /** 235 * Set locations of jar files that contain Hibernate mapping resources, 236 * like "WEB-INF/lib/example.hbm.jar". 237 * <p>Can be used to add to mappings from a Hibernate XML config file, 238 * or to specify all mappings locally. 239 * @see Configuration#addJar(File) 240 */ 241 public void setMappingJarLocations(Resource... mappingJarLocations) { 242 this.mappingJarLocations = mappingJarLocations; 243 } 244 245 /** 246 * Set locations of directories that contain Hibernate mapping resources, 247 * like "WEB-INF/mappings". 248 * <p>Can be used to add to mappings from a Hibernate XML config file, 249 * or to specify all mappings locally. 250 * @see Configuration#addDirectory(File) 251 */ 252 public void setMappingDirectoryLocations(Resource... mappingDirectoryLocations) { 253 this.mappingDirectoryLocations = mappingDirectoryLocations; 254 } 255 256 /** 257 * Set a Hibernate entity interceptor that allows to inspect and change 258 * property values before writing to and reading from the database. 259 * Will get applied to any new Session created by this factory. 260 * @see Configuration#setInterceptor 261 */ 262 public void setEntityInterceptor(Interceptor entityInterceptor) { 263 this.entityInterceptor = entityInterceptor; 264 } 265 266 /** 267 * Set a Hibernate 5 {@link ImplicitNamingStrategy} for the SessionFactory. 268 * @see Configuration#setImplicitNamingStrategy 269 */ 270 public void setImplicitNamingStrategy(ImplicitNamingStrategy implicitNamingStrategy) { 271 this.implicitNamingStrategy = implicitNamingStrategy; 272 } 273 274 /** 275 * Set a Hibernate 5 {@link PhysicalNamingStrategy} for the SessionFactory. 276 * @see Configuration#setPhysicalNamingStrategy 277 */ 278 public void setPhysicalNamingStrategy(PhysicalNamingStrategy physicalNamingStrategy) { 279 this.physicalNamingStrategy = physicalNamingStrategy; 280 } 281 282 /** 283 * Set the Spring {@link org.springframework.transaction.jta.JtaTransactionManager} 284 * or the JTA {@link javax.transaction.TransactionManager} to be used with Hibernate, 285 * if any. Implicitly sets up {@code JtaPlatform}. 286 * @see LocalSessionFactoryBuilder#setJtaTransactionManager 287 */ 288 public void setJtaTransactionManager(Object jtaTransactionManager) { 289 this.jtaTransactionManager = jtaTransactionManager; 290 } 291 292 /** 293 * Set the Hibernate {@link RegionFactory} to use for the SessionFactory. 294 * Allows for using a Spring-managed {@code RegionFactory} instance. 295 * <p>Note: If this is set, the Hibernate settings should not define a 296 * cache provider to avoid meaningless double configuration. 297 * @since 5.1 298 * @see LocalSessionFactoryBuilder#setCacheRegionFactory 299 */ 300 public void setCacheRegionFactory(RegionFactory cacheRegionFactory) { 301 this.cacheRegionFactory = cacheRegionFactory; 302 } 303 304 /** 305 * Set a {@link MultiTenantConnectionProvider} to be passed on to the SessionFactory. 306 * @since 4.3 307 * @see LocalSessionFactoryBuilder#setMultiTenantConnectionProvider 308 */ 309 public void setMultiTenantConnectionProvider(MultiTenantConnectionProvider multiTenantConnectionProvider) { 310 this.multiTenantConnectionProvider = multiTenantConnectionProvider; 311 } 312 313 /** 314 * Set a {@link CurrentTenantIdentifierResolver} to be passed on to the SessionFactory. 315 * @see LocalSessionFactoryBuilder#setCurrentTenantIdentifierResolver 316 */ 317 public void setCurrentTenantIdentifierResolver(CurrentTenantIdentifierResolver currentTenantIdentifierResolver) { 318 this.currentTenantIdentifierResolver = currentTenantIdentifierResolver; 319 } 320 321 /** 322 * Set Hibernate properties, such as "hibernate.dialect". 323 * <p>Note: Do not specify a transaction provider here when using 324 * Spring-driven transactions. It is also advisable to omit connection 325 * provider settings and use a Spring-set DataSource instead. 326 * @see #setDataSource 327 */ 328 public void setHibernateProperties(Properties hibernateProperties) { 329 this.hibernateProperties = hibernateProperties; 330 } 331 332 /** 333 * Return the Hibernate properties, if any. Mainly available for 334 * configuration through property paths that specify individual keys. 335 */ 336 public Properties getHibernateProperties() { 337 if (this.hibernateProperties == null) { 338 this.hibernateProperties = new Properties(); 339 } 340 return this.hibernateProperties; 341 } 342 343 /** 344 * Specify custom type filters for Spring-based scanning for entity classes. 345 * <p>Default is to search all specified packages for classes annotated with 346 * {@code @javax.persistence.Entity}, {@code @javax.persistence.Embeddable} 347 * or {@code @javax.persistence.MappedSuperclass}. 348 * @see #setPackagesToScan 349 */ 350 public void setEntityTypeFilters(TypeFilter... entityTypeFilters) { 351 this.entityTypeFilters = entityTypeFilters; 352 } 353 354 /** 355 * Specify annotated entity classes to register with this Hibernate SessionFactory. 356 * @see Configuration#addAnnotatedClass(Class) 357 */ 358 public void setAnnotatedClasses(Class<?>... annotatedClasses) { 359 this.annotatedClasses = annotatedClasses; 360 } 361 362 /** 363 * Specify the names of annotated packages, for which package-level 364 * annotation metadata will be read. 365 * @see Configuration#addPackage(String) 366 */ 367 public void setAnnotatedPackages(String... annotatedPackages) { 368 this.annotatedPackages = annotatedPackages; 369 } 370 371 /** 372 * Specify packages to search for autodetection of your entity classes in the 373 * classpath. This is analogous to Spring's component-scan feature 374 * ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}). 375 */ 376 public void setPackagesToScan(String... packagesToScan) { 377 this.packagesToScan = packagesToScan; 378 } 379 380 /** 381 * Specify an asynchronous executor for background bootstrapping, 382 * e.g. a {@link org.springframework.core.task.SimpleAsyncTaskExecutor}. 383 * <p>{@code SessionFactory} initialization will then switch into background 384 * bootstrap mode, with a {@code SessionFactory} proxy immediately returned for 385 * injection purposes instead of waiting for Hibernate's bootstrapping to complete. 386 * However, note that the first actual call to a {@code SessionFactory} method will 387 * then block until Hibernate's bootstrapping completed, if not ready by then. 388 * For maximum benefit, make sure to avoid early {@code SessionFactory} calls 389 * in init methods of related beans, even for metadata introspection purposes. 390 * @since 4.3 391 * @see LocalSessionFactoryBuilder#buildSessionFactory(AsyncTaskExecutor) 392 */ 393 public void setBootstrapExecutor(AsyncTaskExecutor bootstrapExecutor) { 394 this.bootstrapExecutor = bootstrapExecutor; 395 } 396 397 /** 398 * Specify one or more Hibernate {@link Integrator} implementations to apply. 399 * <p>This will only be applied for an internally built {@link MetadataSources} 400 * instance. {@link #setMetadataSources} effectively overrides such settings, 401 * with integrators to be applied to the externally built {@link MetadataSources}. 402 * @since 5.1 403 * @see #setMetadataSources 404 * @see BootstrapServiceRegistryBuilder#applyIntegrator 405 */ 406 public void setHibernateIntegrators(Integrator... hibernateIntegrators) { 407 this.hibernateIntegrators = hibernateIntegrators; 408 } 409 410 /** 411 * Specify a Hibernate {@link MetadataSources} service to use (e.g. reusing an 412 * existing one), potentially populated with a custom Hibernate bootstrap 413 * {@link org.hibernate.service.ServiceRegistry} as well. 414 * @since 4.3 415 * @see MetadataSources#MetadataSources(ServiceRegistry) 416 * @see BootstrapServiceRegistryBuilder#build() 417 */ 418 public void setMetadataSources(MetadataSources metadataSources) { 419 this.metadataSourcesAccessed = true; 420 this.metadataSources = metadataSources; 421 } 422 423 /** 424 * Determine the Hibernate {@link MetadataSources} to use. 425 * <p>Can also be externally called to initialize and pre-populate a {@link MetadataSources} 426 * instance which is then going to be used for {@link SessionFactory} building. 427 * @return the MetadataSources to use (never {@code null}) 428 * @since 4.3 429 * @see LocalSessionFactoryBuilder#LocalSessionFactoryBuilder(DataSource, ResourceLoader, MetadataSources) 430 */ 431 public MetadataSources getMetadataSources() { 432 this.metadataSourcesAccessed = true; 433 if (this.metadataSources == null) { 434 BootstrapServiceRegistryBuilder builder = new BootstrapServiceRegistryBuilder(); 435 if (this.resourcePatternResolver != null) { 436 builder = builder.applyClassLoader(this.resourcePatternResolver.getClassLoader()); 437 } 438 if (this.hibernateIntegrators != null) { 439 for (Integrator integrator : this.hibernateIntegrators) { 440 builder = builder.applyIntegrator(integrator); 441 } 442 } 443 this.metadataSources = new MetadataSources(builder.build()); 444 } 445 return this.metadataSources; 446 } 447 448 /** 449 * Specify a Spring {@link ResourceLoader} to use for Hibernate metadata. 450 * @param resourceLoader the ResourceLoader to use (never {@code null}) 451 */ 452 @Override 453 public void setResourceLoader(ResourceLoader resourceLoader) { 454 this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader); 455 } 456 457 /** 458 * Determine the Spring {@link ResourceLoader} to use for Hibernate metadata. 459 * @return the ResourceLoader to use (never {@code null}) 460 * @since 4.3 461 */ 462 public ResourceLoader getResourceLoader() { 463 if (this.resourcePatternResolver == null) { 464 this.resourcePatternResolver = new PathMatchingResourcePatternResolver(); 465 } 466 return this.resourcePatternResolver; 467 } 468 469 /** 470 * Accept the containing {@link BeanFactory}, registering corresponding Hibernate 471 * {@link org.hibernate.resource.beans.container.spi.BeanContainer} integration for 472 * it if possible. This requires a Spring {@link ConfigurableListableBeanFactory} 473 * and Hibernate 5.3 or higher on the classpath. 474 * @since 5.1 475 * @see SpringBeanContainer 476 * @see LocalSessionFactoryBuilder#setBeanContainer 477 */ 478 @Override 479 public void setBeanFactory(BeanFactory beanFactory) { 480 if (beanFactory instanceof ConfigurableListableBeanFactory && 481 ClassUtils.isPresent("org.hibernate.resource.beans.container.spi.BeanContainer", 482 getClass().getClassLoader())) { 483 this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; 484 } 485 } 486 487 488 @Override 489 public void afterPropertiesSet() throws IOException { 490 if (this.metadataSources != null && !this.metadataSourcesAccessed) { 491 // Repeated initialization with no user-customized MetadataSources -> clear it. 492 this.metadataSources = null; 493 } 494 495 LocalSessionFactoryBuilder sfb = new LocalSessionFactoryBuilder( 496 this.dataSource, getResourceLoader(), getMetadataSources()); 497 498 if (this.configLocations != null) { 499 for (Resource resource : this.configLocations) { 500 // Load Hibernate configuration from given location. 501 sfb.configure(resource.getURL()); 502 } 503 } 504 505 if (this.mappingResources != null) { 506 // Register given Hibernate mapping definitions, contained in resource files. 507 for (String mapping : this.mappingResources) { 508 Resource mr = new ClassPathResource(mapping.trim(), getResourceLoader().getClassLoader()); 509 sfb.addInputStream(mr.getInputStream()); 510 } 511 } 512 513 if (this.mappingLocations != null) { 514 // Register given Hibernate mapping definitions, contained in resource files. 515 for (Resource resource : this.mappingLocations) { 516 sfb.addInputStream(resource.getInputStream()); 517 } 518 } 519 520 if (this.cacheableMappingLocations != null) { 521 // Register given cacheable Hibernate mapping definitions, read from the file system. 522 for (Resource resource : this.cacheableMappingLocations) { 523 sfb.addCacheableFile(resource.getFile()); 524 } 525 } 526 527 if (this.mappingJarLocations != null) { 528 // Register given Hibernate mapping definitions, contained in jar files. 529 for (Resource resource : this.mappingJarLocations) { 530 sfb.addJar(resource.getFile()); 531 } 532 } 533 534 if (this.mappingDirectoryLocations != null) { 535 // Register all Hibernate mapping definitions in the given directories. 536 for (Resource resource : this.mappingDirectoryLocations) { 537 File file = resource.getFile(); 538 if (!file.isDirectory()) { 539 throw new IllegalArgumentException( 540 "Mapping directory location [" + resource + "] does not denote a directory"); 541 } 542 sfb.addDirectory(file); 543 } 544 } 545 546 if (this.entityInterceptor != null) { 547 sfb.setInterceptor(this.entityInterceptor); 548 } 549 550 if (this.implicitNamingStrategy != null) { 551 sfb.setImplicitNamingStrategy(this.implicitNamingStrategy); 552 } 553 554 if (this.physicalNamingStrategy != null) { 555 sfb.setPhysicalNamingStrategy(this.physicalNamingStrategy); 556 } 557 558 if (this.jtaTransactionManager != null) { 559 sfb.setJtaTransactionManager(this.jtaTransactionManager); 560 } 561 562 if (this.beanFactory != null) { 563 sfb.setBeanContainer(this.beanFactory); 564 } 565 566 if (this.cacheRegionFactory != null) { 567 sfb.setCacheRegionFactory(this.cacheRegionFactory); 568 } 569 570 if (this.multiTenantConnectionProvider != null) { 571 sfb.setMultiTenantConnectionProvider(this.multiTenantConnectionProvider); 572 } 573 574 if (this.currentTenantIdentifierResolver != null) { 575 sfb.setCurrentTenantIdentifierResolver(this.currentTenantIdentifierResolver); 576 } 577 578 if (this.hibernateProperties != null) { 579 sfb.addProperties(this.hibernateProperties); 580 } 581 582 if (this.entityTypeFilters != null) { 583 sfb.setEntityTypeFilters(this.entityTypeFilters); 584 } 585 586 if (this.annotatedClasses != null) { 587 sfb.addAnnotatedClasses(this.annotatedClasses); 588 } 589 590 if (this.annotatedPackages != null) { 591 sfb.addPackages(this.annotatedPackages); 592 } 593 594 if (this.packagesToScan != null) { 595 sfb.scanPackages(this.packagesToScan); 596 } 597 598 // Build SessionFactory instance. 599 this.configuration = sfb; 600 this.sessionFactory = buildSessionFactory(sfb); 601 } 602 603 /** 604 * Subclasses can override this method to perform custom initialization 605 * of the SessionFactory instance, creating it via the given Configuration 606 * object that got prepared by this LocalSessionFactoryBean. 607 * <p>The default implementation invokes LocalSessionFactoryBuilder's buildSessionFactory. 608 * A custom implementation could prepare the instance in a specific way (e.g. applying 609 * a custom ServiceRegistry) or use a custom SessionFactoryImpl subclass. 610 * @param sfb a LocalSessionFactoryBuilder prepared by this LocalSessionFactoryBean 611 * @return the SessionFactory instance 612 * @see LocalSessionFactoryBuilder#buildSessionFactory 613 */ 614 protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) { 615 return (this.bootstrapExecutor != null ? sfb.buildSessionFactory(this.bootstrapExecutor) : 616 sfb.buildSessionFactory()); 617 } 618 619 /** 620 * Return the Hibernate Configuration object used to build the SessionFactory. 621 * Allows for access to configuration metadata stored there (rarely needed). 622 * @throws IllegalStateException if the Configuration object has not been initialized yet 623 */ 624 public final Configuration getConfiguration() { 625 if (this.configuration == null) { 626 throw new IllegalStateException("Configuration not initialized yet"); 627 } 628 return this.configuration; 629 } 630 631 632 @Override 633 @Nullable 634 public SessionFactory getObject() { 635 return this.sessionFactory; 636 } 637 638 @Override 639 public Class<?> getObjectType() { 640 return (this.sessionFactory != null ? this.sessionFactory.getClass() : SessionFactory.class); 641 } 642 643 @Override 644 public boolean isSingleton() { 645 return true; 646 } 647 648 649 @Override 650 public void destroy() { 651 if (this.sessionFactory != null) { 652 this.sessionFactory.close(); 653 } 654 } 655 656}