HHH-9668 - Document new SessionFactory approach and APIs
This commit is contained in:
parent
37b4aeb7c9
commit
a4b5cf4597
|
@ -0,0 +1,5 @@
|
||||||
|
= Bootstrapping Hibernate JPA
|
||||||
|
:toc:
|
||||||
|
|
||||||
|
* Spec compliant bootstrapping
|
||||||
|
* EntityManagerFactoryBuilder
|
|
@ -0,0 +1,11 @@
|
||||||
|
= Legacy Bootstrapping
|
||||||
|
:toc:
|
||||||
|
|
||||||
|
The legacy way to bootstrap a `SessionFactory` is via the `org.hibernate.cfg.Configuration` object.
|
||||||
|
`Configuration` represents, essentially, a single point for specifying all aspects of building
|
||||||
|
the `SessionFactory`: everything from settings, to mappings, to strategies, etc.
|
||||||
|
|
||||||
|
However there is a huge draw back to this approach which led to the development of the new
|
||||||
|
approach discussed below.
|
||||||
|
|
||||||
|
todo : discuss the timing issues
|
|
@ -0,0 +1,237 @@
|
||||||
|
= Native Bootstrapping
|
||||||
|
:toc:
|
||||||
|
|
||||||
|
This guide discusses the process of bootstrapping a Hibernate `org.hibernate.SessionFactory`. It also
|
||||||
|
discusses the ways in which applications and integrators can hook-in to and affect that process. This
|
||||||
|
bootstrapping process is defined in 2 distinct steps. The first step is the building of a ServiceRegistry
|
||||||
|
holding the services Hibernate will need at bootstrap- and run-time. The second step is the building of
|
||||||
|
a Metadata object representing the mapping information for the application's model and its mapping to
|
||||||
|
the database.
|
||||||
|
|
||||||
|
NOTE : Prior to version 5.0 applications bootstrapped a `SessionFactory` is via the
|
||||||
|
`org.hibernate.cfg.Configuration` object. That approach is still supported in a slightly limited manner.
|
||||||
|
See the _Legacy Bootstrapping_ guide for details.
|
||||||
|
|
||||||
|
|
||||||
|
== Building the ServiceRegistry
|
||||||
|
|
||||||
|
Actually we are concerned with building 2 different ServiceRegistries:
|
||||||
|
|
||||||
|
* `org.hibernate.boot.registry.BootstrapServiceRegistry`
|
||||||
|
* `org.hibernate.boot.registry.StandardServiceRegistry`
|
||||||
|
|
||||||
|
Each of these is built from a builder, `org.hibernate.boot.registry.BootstrapServiceRegistryBuilder`
|
||||||
|
and `org.hibernate.boot.registry.StandardServiceRegistryBuilder` respectively.
|
||||||
|
|
||||||
|
|
||||||
|
NOTE: For more information on ServiceRegistries in general, see the _Services and Registries_ guide.
|
||||||
|
|
||||||
|
=== BootstrapServiceRegistry
|
||||||
|
|
||||||
|
The `BootstrapServiceRegistry` is intended to hold services that Hibernate needs at both bootstrap and run time.
|
||||||
|
This boils down to 3 services:
|
||||||
|
|
||||||
|
* `ClassLoaderService` - which controls how Hibernate interacts with ClassLoaders
|
||||||
|
* `IntegratorService` - which controls the management ands discovery of `org.hibernate.integrator.spi.Integrator` instances.
|
||||||
|
* `StrategySelector` - which control how Hibernate resolves implementations of various strategy
|
||||||
|
contracts. This is a very powerful service, but a full discussion of it is beyond the scope
|
||||||
|
of this guide.
|
||||||
|
|
||||||
|
If you are ok with the default behavior of Hibernate in regards to these BootstrapServiceRegistry services
|
||||||
|
(which is quite often the case, especially in SE environments) building the BootstrapServiceRegistry can be skipped.
|
||||||
|
If you wish to alter how the `BootstrapServiceRegistry` is built, you would use the `BootstrapServiceRegistryBuilder`:
|
||||||
|
|
||||||
|
[[bootstrap-registry-builder-example]]
|
||||||
|
.Building a BootstrapServiceRegistry
|
||||||
|
====
|
||||||
|
[source, JAVA]
|
||||||
|
----
|
||||||
|
BootstrapServiceRegistryBuilder bootstrapRegistryBuilder = new BootstrapServiceRegistryBuilder();
|
||||||
|
// add a special ClassLoader
|
||||||
|
bootstrapRegistryBuilder.with( mySpecialClassLoader );
|
||||||
|
// manually add an Integrator
|
||||||
|
bootstrapRegistryBuilder.with( mySpecialIntegrator );
|
||||||
|
...
|
||||||
|
|
||||||
|
BootstrapServiceRegistry bootstrapRegistry = bootstrapRegistryBuilder.build();
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
The services of the `BootstrapServiceRegistry` cannot be extended (added to) nor overridden (replaced).
|
||||||
|
|
||||||
|
|
||||||
|
=== StandardServiceRegistry
|
||||||
|
|
||||||
|
The services of the `StandardServiceRegistry` may be extended and overridden.
|
||||||
|
|
||||||
|
A `StandardServiceRegistry` is built through the `StandardServiceRegistryBuilder` which can be constructed in
|
||||||
|
one of 2 ways:
|
||||||
|
|
||||||
|
[[standard-registry-builder-example1]]
|
||||||
|
.Building a StandardServiceRegistryBuilder with a supplied BootstrapServiceRegistry
|
||||||
|
====
|
||||||
|
[source, JAVA]
|
||||||
|
----
|
||||||
|
BootstrapServiceRegistry bootstrapRegistry = ...;
|
||||||
|
StandardServiceRegistryBuilder standardRegistryBuilder = new StandardServiceRegistryBuilder( bootstrapRegistry );
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
[[standard-registry-builder-example2]]
|
||||||
|
.Building a StandardServiceRegistryBuilder without a supplied BootstrapServiceRegistry
|
||||||
|
====
|
||||||
|
[source, JAVA]
|
||||||
|
----
|
||||||
|
StandardServiceRegistryBuilder standardRegistryBuilder = new StandardServiceRegistryBuilder();
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
The second form will create a `BootstrapServiceRegistry` on the fly with default behavior.
|
||||||
|
|
||||||
|
A `StandardServiceRegistry` is also highly configurable via the `StandardServiceRegistryBuilder` API. See the
|
||||||
|
`StandardServiceRegistryBuilder` javadocs for full details. Some specific methods of interest:
|
||||||
|
|
||||||
|
[[standard-registry-builder-example3]]
|
||||||
|
.Configuring StandardServiceRegistryBuilder
|
||||||
|
====
|
||||||
|
[source, JAVA]
|
||||||
|
----
|
||||||
|
StandardServiceRegistryBuilder standardRegistryBuilder = ...;
|
||||||
|
// load some properties via resource lookup
|
||||||
|
standardRegistryBuilder.loadProperties( "org/hibernate/example/MyProperties.properties" );
|
||||||
|
// configure the registry from a resource lookup for a cfg.xml config file
|
||||||
|
standardRegistryBuilder.configure( "org/hibernate/example/MyCfg.xml" );
|
||||||
|
// apply a random setting
|
||||||
|
standardRegistryBuilder.applySetting( "myProp", "some value" );
|
||||||
|
// apply a service initiator
|
||||||
|
standardRegistryBuilder.addInitiator( new CustomServiceInitiator() );
|
||||||
|
// apply a service impl
|
||||||
|
standardRegistryBuilder.addService( SomeCustomService.class, new SomeCustomServiceImpl() );
|
||||||
|
|
||||||
|
// and finally build the StandardServiceRegistry
|
||||||
|
StandardServiceRegistry standardRegistry = standardRegistryBuilder.build();
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
|
||||||
|
== Building the Metadata
|
||||||
|
|
||||||
|
The `org.hibernate.boot.Metadata` object contains the parsed representations of an application's
|
||||||
|
domain model and its mapping to a database. The first thing we obviously need to build a parsed
|
||||||
|
representation is the source information to be parsed. This is the purpose of
|
||||||
|
`org.hibernate.boot.MetadataSources`.
|
||||||
|
|
||||||
|
|
||||||
|
[[MetadataSources-example]]
|
||||||
|
.Configuring a MetadataSources
|
||||||
|
====
|
||||||
|
[source, JAVA]
|
||||||
|
----
|
||||||
|
MetadataSources sources = new MetadataSources( standardRegistry );
|
||||||
|
// alternatively, we can build the MetadataSources without passing
|
||||||
|
// a service registry, in which case it will build a default
|
||||||
|
// BootstrapServiceRegistry to use
|
||||||
|
// MetadataSources sources = new MetadataSources();
|
||||||
|
|
||||||
|
// add a class using JPA/Hibernate annotations for mapping
|
||||||
|
sources.addAnnotatedClass( MyEntity.class );
|
||||||
|
|
||||||
|
// add the name of a class using JPA/Hibernate annotations for mapping.
|
||||||
|
// differs from above in that accessing the Class is deferred which is
|
||||||
|
// important if using runtime bytecode-enhancement
|
||||||
|
sources.addAnnotatedClassName( "org.hibernate.example.Customer" );
|
||||||
|
|
||||||
|
// Adds the named hbm.xml resource as a source: which performs the
|
||||||
|
// classpath lookup and parses the XML
|
||||||
|
sources.addResource( "org/hibernate/example/Order.hbm.xml" );
|
||||||
|
|
||||||
|
// Adds the named JPA orm.xml resource as a source: which performs the
|
||||||
|
// classpath lookup and parses the XML
|
||||||
|
sources.addResource( "org/hibernate/example/Product.orm.xml" );
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
`MetadataSources` has many other methods as well; explore its API and javadocs for more information. Also,
|
||||||
|
all methods on `MetadataSources` allow for chaining should you prefer that style.
|
||||||
|
|
||||||
|
[[MetadataSources-chaining-example]]
|
||||||
|
.Configuring a MetadataSources with method chaining
|
||||||
|
====
|
||||||
|
[source, JAVA]
|
||||||
|
----
|
||||||
|
MetadataSources sources = new MetadataSources( standardRegistry )
|
||||||
|
.addAnnotatedClass( MyEntity.class )
|
||||||
|
.addAnnotatedClassName( "org.hibernate.example.Customer" )
|
||||||
|
.addResource( "org/hibernate/example/Order.hbm.xml" )
|
||||||
|
.addResource( "org/hibernate/example/Product.orm.xml" );
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
Once we have the sources of mapping information defined, we need to build the `Metadata` object. If you are
|
||||||
|
ok with the default behavior in building the `Metadata` (or if relying on a `MetadataBuilderContributor` - see below)
|
||||||
|
then you can simply call `MetadataSources#buildMetadata`.
|
||||||
|
|
||||||
|
NOTE : Notice that a ServiceRegistry can be passed at a number of points in this bootstrapping process. The suggested
|
||||||
|
approach is to build a `StandardServiceRegistry` yourself and pass that along to the `MetadataSources` constructor.
|
||||||
|
From there, `MetadataBuilder`, `Metadata`, `SessionFactoryBuilder` and `SessionFactory` will all pick up that
|
||||||
|
same `StandardServiceRegistry`.
|
||||||
|
|
||||||
|
However, if you wish to adjust the process of building `Metadata` from `MetadataSources` you will need to use
|
||||||
|
the `MetadataBuilder` as obtained via `MetadataSources#getMetadataBuilder`. `MetadataBuilder` allows a lot of control
|
||||||
|
over the `Metadata` building process. See its javadocs for full details.
|
||||||
|
|
||||||
|
[[MetadataBuilder-example]]
|
||||||
|
.Building Metadata via MetadataBuilder
|
||||||
|
====
|
||||||
|
[source, JAVA]
|
||||||
|
----
|
||||||
|
MetadataBuilder metadataBuilder = sources.getMetadataBuilder();
|
||||||
|
|
||||||
|
// Use the JPA-compliant implicit naming strategy
|
||||||
|
metadataBuilder.with( ImplicitNamingStrategyJpaCompliantImpl.INSTANCE );
|
||||||
|
|
||||||
|
// specify the schema name to use for tables, etc when none is explicitly specified
|
||||||
|
metadataBuilder.withImplicitSchemaName( "my_default_schema" );
|
||||||
|
|
||||||
|
Metadata metadata = metadataBuilder.build();
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
== Building the SessionFactory
|
||||||
|
|
||||||
|
Much like we've discussed above, if you are ok with the default behavior of building a `SessionFactory`
|
||||||
|
from a `Metadata` reference, you can simply call `Metadata#buildSessionFactory`. However, if you would like to
|
||||||
|
adjust that building process you will need to use `SessionFactoryBuilder` as obtained via
|
||||||
|
`Metadata#getSessionFactoryBuilder`. See the `SessionFactoryBuilder` javadocs for details of the control it allows
|
||||||
|
over the `SessionFactory` building process.
|
||||||
|
|
||||||
|
[[SessionFactoryBuilder-example]]
|
||||||
|
.Building SessionFactory via SessionFactoryBuilder
|
||||||
|
====
|
||||||
|
[source, JAVA]
|
||||||
|
----
|
||||||
|
SessionFactoryBuilder sessionFactoryBuilder = metadata.getSessionFactoryBuilder();
|
||||||
|
|
||||||
|
// Supply an SessionFactory-level Interceptor
|
||||||
|
sessionFactoryBuilder.with( new MySessionFactoryInterceptor() );
|
||||||
|
|
||||||
|
// Add a custom observer
|
||||||
|
sessionFactoryBuilder.add( new MySessionFactoryObserver() );
|
||||||
|
|
||||||
|
// Apply a CDI BeanManager (for JPA event listeners)
|
||||||
|
sessionFactoryBuilder.withBeanManager( getBeanManagerFromSomewhere() );
|
||||||
|
|
||||||
|
SessionFactory sessionFactory = sessionFactoryBuilder.build();
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
== Putting It All Together
|
||||||
|
|
||||||
|
== Integration Points
|
||||||
|
|
||||||
|
=== Integrator
|
||||||
|
=== ServiceContributor
|
||||||
|
=== TypeContributor
|
||||||
|
=== MetadataSourcesContributor
|
||||||
|
=== MetadataBuilderContributor
|
||||||
|
=== SessionFactoryBuilderContributor (todo)
|
|
@ -8,6 +8,10 @@ NOTE: This is still very much a work in progress. <<helping,Help>> is definitely
|
||||||
|
|
||||||
== User Guides
|
== User Guides
|
||||||
|
|
||||||
|
* For information on bootstrapping Hibernate
|
||||||
|
** For bootstrapping a SessionFactory, see the <<bootstrap/NativeBootstrapping.adoc#,Native Bootstrapping Guide>>
|
||||||
|
** For bootstrapping a Hibernate EntityManagerFactory (JPA), see the <<bootstrap/JpaBootstrapping.adoc#,JPA Bootstrapping Guide>>
|
||||||
|
** For (semi-deprecated) bootstrapping of a SessionFactory using the legacy Configuration approach, see the <<bootstrap/LegacyBootstrapping.adoc#,Legacy Bootstrapping Guide>>
|
||||||
* For information on generated (non-identifier) values, see the <<generated/GeneratedValues.adoc#,Generated Values Guide>>
|
* For information on generated (non-identifier) values, see the <<generated/GeneratedValues.adoc#,Generated Values Guide>>
|
||||||
* For information on logging, see <<logging/Logging.adoc#,Logging Guide>>
|
* For information on logging, see <<logging/Logging.adoc#,Logging Guide>>
|
||||||
* Others coming soon
|
* Others coming soon
|
||||||
|
|
|
@ -207,7 +207,9 @@ public class MetadataSources implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read metadata from the annotations attached to the given class.
|
* Read metadata from the annotations attached to the given class. The important
|
||||||
|
* distinction here is that the {@link Class} will not be accessed until later
|
||||||
|
* which is important for on-the-fly bytecode-enhancement
|
||||||
*
|
*
|
||||||
* @param annotatedClassName The name of a class containing annotations
|
* @param annotatedClassName The name of a class containing annotations
|
||||||
*
|
*
|
||||||
|
|
|
@ -686,6 +686,10 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populate(MetadataBuilder metamodelBuilder, MergedSettings mergedSettings, StandardServiceRegistry ssr) {
|
private void populate(MetadataBuilder metamodelBuilder, MergedSettings mergedSettings, StandardServiceRegistry ssr) {
|
||||||
|
if ( persistenceUnit.getTempClassLoader() != null ) {
|
||||||
|
metamodelBuilder.with( persistenceUnit.getTempClassLoader() );
|
||||||
|
}
|
||||||
|
|
||||||
metamodelBuilder.with( new StandardJpaScanEnvironmentImpl( persistenceUnit ) );
|
metamodelBuilder.with( new StandardJpaScanEnvironmentImpl( persistenceUnit ) );
|
||||||
metamodelBuilder.with(
|
metamodelBuilder.with(
|
||||||
new StandardScanOptions(
|
new StandardScanOptions(
|
||||||
|
|
|
@ -195,6 +195,11 @@ public class ParsedPersistenceXmlDescriptor implements org.hibernate.jpa.boot.sp
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClassLoader getTempClassLoader() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void pushClassTransformer(List<String> entityClassNames) {
|
public void pushClassTransformer(List<String> entityClassNames) {
|
||||||
// todo : log a message that this is currently not supported...
|
// todo : log a message that this is currently not supported...
|
||||||
|
|
|
@ -89,6 +89,11 @@ public class PersistenceUnitInfoDescriptor implements PersistenceUnitDescriptor
|
||||||
return persistenceUnitInfo.getClassLoader();
|
return persistenceUnitInfo.getClassLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClassLoader getTempClassLoader() {
|
||||||
|
return persistenceUnitInfo.getNewTempClassLoader();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isExcludeUnlistedClasses() {
|
public boolean isExcludeUnlistedClasses() {
|
||||||
return persistenceUnitInfo.excludeUnlistedClasses();
|
return persistenceUnitInfo.excludeUnlistedClasses();
|
||||||
|
|
|
@ -96,6 +96,7 @@ public interface PersistenceUnitDescriptor {
|
||||||
public Properties getProperties();
|
public Properties getProperties();
|
||||||
|
|
||||||
public ClassLoader getClassLoader();
|
public ClassLoader getClassLoader();
|
||||||
|
public ClassLoader getTempClassLoader();
|
||||||
|
|
||||||
public void pushClassTransformer(List<String> entityClassNames);
|
public void pushClassTransformer(List<String> entityClassNames);
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,6 +188,11 @@ public abstract class BaseEntityManagerFunctionalTestCase extends BaseUnitTestCa
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClassLoader getTempClassLoader() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void pushClassTransformer(List<String> entityClassNames) {
|
public void pushClassTransformer(List<String> entityClassNames) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,6 +120,11 @@ public class PersistenceUnitDescriptorAdapter implements PersistenceUnitDescript
|
||||||
return Thread.currentThread().getContextClassLoader();
|
return Thread.currentThread().getContextClassLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClassLoader getTempClassLoader() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void pushClassTransformer(List<String> entityClassNames) {
|
public void pushClassTransformer(List<String> entityClassNames) {
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue