HHH-12133 Comply with API docs with respect to lifecycle management depending on the 'shouldRegistryManageLifecycle' parameter

The registry should not manage the bean lifecycle when
'shouldRegistryManageLifecycle' is false. The easiest way to do so is to
use BeanManager.createInstance to retrieve beans in the Standard CDI lifecycle
strategy: it correctly retrieves singletons from the CDI context instead
of instantiating them again.

Also, fix javax.enterprise.inject.spi.Bean-based instance destructions:
we used to only request destruction to the creational context, which is
wrong because it may skip the execution of @PostDestroy methods in
particular.
This commit is contained in:
Yoann Rodière 2017-12-18 18:27:12 +01:00 committed by Steve Ebersole
parent b3ac2feddf
commit edc0039afc
8 changed files with 76 additions and 62 deletions

View File

@ -22,24 +22,6 @@ public class Helper {
private Helper() { private Helper() {
} }
@SuppressWarnings("unchecked")
public <T> Bean<T> getBean(Class<T> beanContract, BeanManager beanManager) {
Set<Bean<?>> beans = beanManager.getBeans( beanContract );
if ( beans.isEmpty() ) {
throw new IllegalArgumentException(
"BeanManager returned no matching beans: contract = " + beanContract.getName()
);
}
if ( beans.size() > 1 ) {
throw new IllegalArgumentException(
"BeanManager returned multiple matching beans: contract = " + beanContract.getName()
);
}
return (Bean<T>) beans.iterator().next();
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> Bean<T> getNamedBean(String beanName, Class<T> beanContract, BeanManager beanManager) { public <T> Bean<T> getNamedBean(String beanName, Class<T> beanContract, BeanManager beanManager) {
Set<Bean<?>> beans = beanManager.getBeans( beanContract, new NamedBeanQualifier( beanName ) ); Set<Bean<?>> beans = beanManager.getBeans( beanContract, new NamedBeanQualifier( beanName ) );
@ -57,4 +39,13 @@ public class Helper {
return (Bean<T>) beans.iterator().next(); return (Bean<T>) beans.iterator().next();
} }
public CdiLifecycleManagementStrategy getLifecycleManagementStrategy(boolean shouldRegistryManageLifecycle) {
if ( shouldRegistryManageLifecycle ) {
return JpaCdiLifecycleManagementStrategy.INSTANCE;
}
else {
return StandardCdiLifecycleManagementStrategy.INSTANCE;
}
}
} }

View File

@ -14,6 +14,18 @@ import javax.enterprise.inject.spi.InjectionTarget;
import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.resource.beans.spi.ManagedBean;
/**
* A {@link CdiLifecycleManagementStrategy} to use when JPA compliance is required
* (i.e. when the bean lifecycle is to be managed by the JPA runtime, not the CDI runtime).
*
* The main characteristic of this strategy is that each requested bean is instantiated directly
* and guaranteed to not be shared in the CDI context.
*
* In particular, @Singleton-scoped or @ApplicationScoped beans are instantiated directly by this strategy,
* even if there is already an instance in the CDI context.
* This means singletons are not really singletons, but this seems to be the behavior required by
* the JPA 2.2 spec.
*/
class JpaCdiLifecycleManagementStrategy implements CdiLifecycleManagementStrategy { class JpaCdiLifecycleManagementStrategy implements CdiLifecycleManagementStrategy {
static final JpaCdiLifecycleManagementStrategy INSTANCE = new JpaCdiLifecycleManagementStrategy(); static final JpaCdiLifecycleManagementStrategy INSTANCE = new JpaCdiLifecycleManagementStrategy();
@ -44,7 +56,7 @@ class JpaCdiLifecycleManagementStrategy implements CdiLifecycleManagementStrateg
T beanInstance = bean.create( creationalContext ); T beanInstance = bean.create( creationalContext );
return new NamedJpaManagedBeanImpl<>( beanClass, creationalContext, beanInstance ); return new NamedJpaManagedBeanImpl<>( beanClass, bean, creationalContext, beanInstance );
} }
private static class JpaManagedBeanImpl<T> implements ManagedBean<T> { private static class JpaManagedBeanImpl<T> implements ManagedBean<T> {
@ -82,13 +94,14 @@ class JpaCdiLifecycleManagementStrategy implements CdiLifecycleManagementStrateg
private static class NamedJpaManagedBeanImpl<T> implements ManagedBean<T> { private static class NamedJpaManagedBeanImpl<T> implements ManagedBean<T> {
private final Class<T> beanClass; private final Class<T> beanClass;
private final Bean<T> bean;
private final CreationalContext<T> creationContext; private final CreationalContext<T> creationContext;
private final T beanInstance; private final T beanInstance;
private NamedJpaManagedBeanImpl( private NamedJpaManagedBeanImpl(
Class<T> beanClass, Class<T> beanClass, Bean<T> bean, CreationalContext<T> creationContext, T beanInstance) {
CreationalContext<T> creationContext, T beanInstance) {
this.beanClass = beanClass; this.beanClass = beanClass;
this.bean = bean;
this.creationContext = creationContext; this.creationContext = creationContext;
this.beanInstance = beanInstance; this.beanInstance = beanInstance;
} }
@ -105,7 +118,7 @@ class JpaCdiLifecycleManagementStrategy implements CdiLifecycleManagementStrateg
@Override @Override
public void release() { public void release() {
creationContext.release(); bean.destroy( beanInstance, creationContext );
} }
} }
} }

View File

@ -33,13 +33,15 @@ public class ManagedBeanRegistryCdiDelayedImpl extends AbstractManagedBeanRegist
} }
@Override @Override
protected <T> ManagedBean<T> createBean(Class<T> beanClass) { protected <T> ManagedBean<T> createBean(Class<T> beanClass, boolean shouldRegistryManageLifecycle) {
return new LazilyInitializedManagedBeanImpl<>( beanClass, JpaCdiLifecycleManagementStrategy.INSTANCE ); return new LazilyInitializedManagedBeanImpl<>( beanClass,
Helper.INSTANCE.getLifecycleManagementStrategy( shouldRegistryManageLifecycle ) );
} }
@Override @Override
protected <T> ManagedBean<T> createBean(String beanName, Class<T> beanContract) { protected <T> ManagedBean<T> createBean(String beanName, Class<T> beanContract, boolean shouldRegistryManageLifecycle) {
return new LazilyInitializedNamedManagedBeanImpl<>( beanName, beanContract, StandardCdiLifecycleManagementStrategy.INSTANCE ); return new LazilyInitializedNamedManagedBeanImpl<>( beanName, beanContract,
Helper.INSTANCE.getLifecycleManagementStrategy( shouldRegistryManageLifecycle ) );
} }
/** /**

View File

@ -39,13 +39,15 @@ public class ManagedBeanRegistryCdiExtendedImpl
} }
@Override @Override
protected <T> ManagedBean<T> createBean(Class<T> beanClass) { protected <T> ManagedBean<T> createBean(Class<T> beanClass, boolean shouldRegistryManageLifecycle) {
return new LazilyInitializedManagedBeanImpl<>( beanClass, JpaCdiLifecycleManagementStrategy.INSTANCE ); return new LazilyInitializedManagedBeanImpl<>( beanClass,
Helper.INSTANCE.getLifecycleManagementStrategy( shouldRegistryManageLifecycle ) );
} }
@Override @Override
protected <T> ManagedBean<T> createBean(String beanName, Class<T> beanContract) { protected <T> ManagedBean<T> createBean(String beanName, Class<T> beanContract, boolean shouldRegistryManageLifecycle) {
return new LazilyInitializedNamedManagedBeanImpl<>( beanName, beanContract, StandardCdiLifecycleManagementStrategy.INSTANCE ); return new LazilyInitializedNamedManagedBeanImpl<>( beanName, beanContract,
Helper.INSTANCE.getLifecycleManagementStrategy( shouldRegistryManageLifecycle ) );
} }
@Override @Override

View File

@ -34,12 +34,14 @@ class ManagedBeanRegistryCdiStandardImpl extends AbstractManagedBeanRegistry {
} }
@Override @Override
protected <T> ManagedBean<T> createBean(Class<T> beanClass) { protected <T> ManagedBean<T> createBean(Class<T> beanClass, boolean shouldRegistryManageLifecycle) {
return JpaCdiLifecycleManagementStrategy.INSTANCE.createBean( beanManager, beanClass ); return Helper.INSTANCE.getLifecycleManagementStrategy( shouldRegistryManageLifecycle )
.createBean( beanManager, beanClass );
} }
@Override @Override
protected <T> ManagedBean<T> createBean(String beanName, Class<T> beanContract) { protected <T> ManagedBean<T> createBean(String beanName, Class<T> beanContract, boolean shouldRegistryManageLifecycle) {
return StandardCdiLifecycleManagementStrategy.INSTANCE.createBean( beanManager, beanName, beanContract ); return Helper.INSTANCE.getLifecycleManagementStrategy( shouldRegistryManageLifecycle )
.createBean( beanManager, beanName, beanContract );
} }
} }

View File

@ -23,12 +23,15 @@ public class ManagedBeanRegistryDirectImpl extends AbstractManagedBeanRegistry {
} }
@Override @Override
protected <T> ManagedBean<T> createBean(Class<T> beanClass) { protected <T> ManagedBean<T> createBean(Class<T> beanClass, boolean shouldRegistryManageLifecycle) {
return new DirectInstantiationManagedBeanImpl<>( beanClass ); return new DirectInstantiationManagedBeanImpl<>( beanClass );
} }
@Override @Override
protected <T> ManagedBean<T> createBean(String beanName, Class<T> beanContract) { protected <T> ManagedBean<T> createBean(
String beanName,
Class<T> beanContract,
boolean shouldRegistryManageLifecycle) {
return new DirectInstantiationManagedBeanImpl<>( beanContract ); return new DirectInstantiationManagedBeanImpl<>( beanContract );
} }
} }

View File

@ -6,12 +6,21 @@
*/ */
package org.hibernate.resource.beans.internal; package org.hibernate.resource.beans.internal;
import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.inject.Instance;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager; import javax.enterprise.inject.spi.BeanManager;
import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.resource.beans.spi.ManagedBean;
/**
* A {@link CdiLifecycleManagementStrategy} to use when CDI compliance is required
* (i.e. when the bean lifecycle is to be managed by the CDI runtime, not the JPA runtime).
*
* The main characteristic of this strategy is that every create/destroy operation is delegated
* to the CDI runtime.
*
* In particular, @Singleton-scoped or @ApplicationScoped beans are retrieved from the CDI context,
* and are not duplicated, in contrast to {@link JpaCdiLifecycleManagementStrategy}.
*/
class StandardCdiLifecycleManagementStrategy implements CdiLifecycleManagementStrategy { class StandardCdiLifecycleManagementStrategy implements CdiLifecycleManagementStrategy {
static final StandardCdiLifecycleManagementStrategy INSTANCE = new StandardCdiLifecycleManagementStrategy(); static final StandardCdiLifecycleManagementStrategy INSTANCE = new StandardCdiLifecycleManagementStrategy();
@ -22,38 +31,30 @@ class StandardCdiLifecycleManagementStrategy implements CdiLifecycleManagementSt
@Override @Override
public <T> ManagedBean<T> createBean(BeanManager beanManager, Class<T> beanClass) { public <T> ManagedBean<T> createBean(BeanManager beanManager, Class<T> beanClass) {
Bean<T> bean = Helper.INSTANCE.getBean( beanClass, beanManager ); Instance<T> instance = beanManager.createInstance().select( beanClass );
T beanInstance = instance.get();
// Pass the bean to createCreationalContext here so that an existing instance can be returned return new BeanManagerManagedBeanImpl<>( beanClass, instance, beanInstance );
CreationalContext<T> creationalContext = beanManager.createCreationalContext( bean );
T beanInstance = bean.create( creationalContext );
return new BeanManagerManagedBeanImpl<>( beanClass, creationalContext, beanInstance );
} }
@Override @Override
public <T> ManagedBean<T> createBean(BeanManager beanManager, String beanName, Class<T> beanClass) { public <T> ManagedBean<T> createBean(BeanManager beanManager, String beanName, Class<T> beanClass) {
Bean<T> bean = Helper.INSTANCE.getNamedBean( beanName, beanClass, beanManager ); Instance<T> instance = beanManager.createInstance().select( beanClass, new NamedBeanQualifier( beanName ) );
T beanInstance = instance.get();
// Pass the bean to createCreationalContext here so that an existing instance can be returned return new BeanManagerManagedBeanImpl<>( beanClass, instance, beanInstance );
CreationalContext<T> creationalContext = beanManager.createCreationalContext( bean );
T beanInstance = bean.create( creationalContext );
return new BeanManagerManagedBeanImpl<>( beanClass, creationalContext, beanInstance );
} }
private static class BeanManagerManagedBeanImpl<T> implements ManagedBean<T> { private static class BeanManagerManagedBeanImpl<T> implements ManagedBean<T> {
private final Class<T> beanClass; private final Class<T> beanClass;
private final CreationalContext<T> creationContext; private final Instance<T> instance;
private final T beanInstance; private final T beanInstance;
private BeanManagerManagedBeanImpl( private BeanManagerManagedBeanImpl(
Class<T> beanClass, Class<T> beanClass,
CreationalContext<T> creationContext, T beanInstance) { Instance<T> instance, T beanInstance) {
this.beanClass = beanClass; this.beanClass = beanClass;
this.creationContext = creationContext; this.instance = instance;
this.beanInstance = beanInstance; this.beanInstance = beanInstance;
} }
@ -69,7 +70,7 @@ class StandardCdiLifecycleManagementStrategy implements CdiLifecycleManagementSt
@Override @Override
public void release() { public void release() {
creationContext.release(); instance.destroy( beanInstance );
} }
} }
} }

View File

@ -27,7 +27,7 @@ public abstract class AbstractManagedBeanRegistry implements ManagedBeanRegistry
return getCacheableBean( beanClass ); return getCacheableBean( beanClass );
} }
else { else {
return createBean( beanClass ); return createBean( beanClass, shouldRegistryManageLifecycle );
} }
} }
@ -39,13 +39,13 @@ public abstract class AbstractManagedBeanRegistry implements ManagedBeanRegistry
return existing; return existing;
} }
final ManagedBean<T> bean = createBean( beanClass ); final ManagedBean<T> bean = createBean( beanClass, true );
registrations.put( beanName, bean ); registrations.put( beanName, bean );
return bean; return bean;
} }
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
protected abstract <T> ManagedBean<T> createBean(Class<T> beanClass); protected abstract <T> ManagedBean<T> createBean(Class<T> beanClass, boolean shouldRegistryManageLifecycle);
@Override @Override
public <T> ManagedBean<T> getBean(String beanName, Class<T> beanContract, boolean shouldRegistryManageLifecycle) { public <T> ManagedBean<T> getBean(String beanName, Class<T> beanContract, boolean shouldRegistryManageLifecycle) {
@ -53,7 +53,7 @@ public abstract class AbstractManagedBeanRegistry implements ManagedBeanRegistry
return getCacheableBean( beanName, beanContract ); return getCacheableBean( beanName, beanContract );
} }
else { else {
return createBean( beanName, beanContract ); return createBean( beanName, beanContract, shouldRegistryManageLifecycle );
} }
} }
@ -64,13 +64,13 @@ public abstract class AbstractManagedBeanRegistry implements ManagedBeanRegistry
return existing; return existing;
} }
final ManagedBean<T> bean = createBean( beanName, beanContract ); final ManagedBean<T> bean = createBean( beanName, beanContract, false );
registrations.put( beanName, bean ); registrations.put( beanName, bean );
return bean; return bean;
} }
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
protected abstract <T> ManagedBean<T> createBean(String beanName, Class<T> beanContract); protected abstract <T> ManagedBean<T> createBean(String beanName, Class<T> beanContract, boolean shouldRegistryManageLifecycle);
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
protected void forEachBean(Consumer<ManagedBean<?>> consumer) { protected void forEachBean(Consumer<ManagedBean<?>> consumer) {