HHH-12133 Move CDI lifecycle management code to dedicated strategies

This commit should not change the current behavior, it is only about
moving code to separate classes to make the following changes clearer.
This commit is contained in:
Yoann Rodière 2017-12-18 18:20:38 +01:00 committed by Steve Ebersole
parent c03fdf84d4
commit b3ac2feddf
8 changed files with 362 additions and 203 deletions

View File

@ -0,0 +1,19 @@
/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.resource.beans.internal;
import javax.enterprise.inject.spi.BeanManager;
import org.hibernate.resource.beans.spi.ManagedBean;
interface CdiLifecycleManagementStrategy {
<T> ManagedBean<T> createBean(BeanManager beanManager, Class<T> beanClass);
<T> ManagedBean<T> createBean(BeanManager beanManager, String beanName, Class<T> beanClass);
}

View File

@ -22,6 +22,24 @@ public class 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")
public <T> Bean<T> getNamedBean(String beanName, Class<T> beanContract, BeanManager beanManager) {
Set<Bean<?>> beans = beanManager.getBeans( beanContract, new NamedBeanQualifier( beanName ) );

View File

@ -0,0 +1,111 @@
/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.resource.beans.internal;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.InjectionTarget;
import org.hibernate.resource.beans.spi.ManagedBean;
class JpaCdiLifecycleManagementStrategy implements CdiLifecycleManagementStrategy {
static final JpaCdiLifecycleManagementStrategy INSTANCE = new JpaCdiLifecycleManagementStrategy();
private JpaCdiLifecycleManagementStrategy() {
// private constructor, do not use
}
@Override
public <T> ManagedBean<T> createBean(BeanManager beanManager, Class<T> beanClass) {
AnnotatedType<T> annotatedType = beanManager.createAnnotatedType( beanClass );
InjectionTarget<T> injectionTarget = beanManager.createInjectionTarget( annotatedType );
CreationalContext<T> creationalContext = beanManager.createCreationalContext( null );
T beanInstance = injectionTarget.produce( creationalContext );
injectionTarget.inject( beanInstance, creationalContext );
injectionTarget.postConstruct( beanInstance );
return new JpaManagedBeanImpl<>( beanClass, injectionTarget, creationalContext, beanInstance );
}
@Override
public <T> ManagedBean<T> createBean(BeanManager beanManager, String beanName, Class<T> beanClass) {
Bean<T> bean = Helper.INSTANCE.getNamedBean( beanName, beanClass, beanManager );
CreationalContext<T> creationalContext = beanManager.createCreationalContext( null );
T beanInstance = bean.create( creationalContext );
return new NamedJpaManagedBeanImpl<>( beanClass, creationalContext, beanInstance );
}
private static class JpaManagedBeanImpl<T> implements ManagedBean<T> {
private final Class<T> beanClass;
private final InjectionTarget<T> injectionTarget;
private final CreationalContext<T> creationContext;
private final T beanInstance;
private JpaManagedBeanImpl(
Class<T> beanClass,
InjectionTarget<T> injectionTarget, CreationalContext<T> creationContext, T beanInstance) {
this.beanClass = beanClass;
this.injectionTarget = injectionTarget;
this.creationContext = creationContext;
this.beanInstance = beanInstance;
}
@Override
public Class<T> getBeanClass() {
return beanClass;
}
@Override
public T getBeanInstance() {
return beanInstance;
}
@Override
public void release() {
injectionTarget.preDestroy( beanInstance );
injectionTarget.dispose( beanInstance );
creationContext.release();
}
}
private static class NamedJpaManagedBeanImpl<T> implements ManagedBean<T> {
private final Class<T> beanClass;
private final CreationalContext<T> creationContext;
private final T beanInstance;
private NamedJpaManagedBeanImpl(
Class<T> beanClass,
CreationalContext<T> creationContext, T beanInstance) {
this.beanClass = beanClass;
this.creationContext = creationContext;
this.beanInstance = beanInstance;
}
@Override
public Class<T> getBeanClass() {
return beanClass;
}
@Override
public T getBeanInstance() {
return beanInstance;
}
@Override
public void release() {
creationContext.release();
}
}
}

View File

@ -6,12 +6,7 @@
*/
package org.hibernate.resource.beans.internal;
import java.util.Set;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.InjectionTarget;
import org.hibernate.resource.beans.spi.AbstractManagedBeanRegistry;
import org.hibernate.resource.beans.spi.ManagedBean;
@ -39,25 +34,29 @@ public class ManagedBeanRegistryCdiDelayedImpl extends AbstractManagedBeanRegist
@Override
protected <T> ManagedBean<T> createBean(Class<T> beanClass) {
return new ManagedBeanImpl<>( beanClass );
return new LazilyInitializedManagedBeanImpl<>( beanClass, JpaCdiLifecycleManagementStrategy.INSTANCE );
}
@Override
protected <T> ManagedBean<T> createBean(String beanName, Class<T> beanContract) {
return new NamedManagedBeanImpl<>( beanName, beanContract );
return new LazilyInitializedNamedManagedBeanImpl<>( beanName, beanContract, StandardCdiLifecycleManagementStrategy.INSTANCE );
}
private class ManagedBeanImpl<T> implements ManagedBean<T> {
/**
* A {@link ManagedBean} that is initialized upon the first call to {@link #getBeanInstance()},
* relying on a {@link CdiLifecycleManagementStrategy} to initialize a delegate.
*
* @param <T> The type of bean instances
*/
private class LazilyInitializedManagedBeanImpl<T> implements ManagedBean<T> {
private final Class<T> beanClass;
private final CdiLifecycleManagementStrategy strategy;
private boolean initialized = false;
private ManagedBean<T> delegate = null;
private InjectionTarget<T> injectionTarget;
private CreationalContext<T> creationContext;
private T beanInstance;
ManagedBeanImpl(Class<T> beanClass) {
LazilyInitializedManagedBeanImpl(Class<T> beanClass, CdiLifecycleManagementStrategy strategy) {
this.beanClass = beanClass;
this.strategy = strategy;
}
@Override
@ -67,56 +66,50 @@ public class ManagedBeanRegistryCdiDelayedImpl extends AbstractManagedBeanRegist
@Override
public T getBeanInstance() {
if ( !initialized ) {
if ( delegate == null ) {
initialize();
}
return beanInstance;
return delegate.getBeanInstance();
}
private void initialize() {
log.debug( "Delayed initialization of CDI bean on first use : " + beanClass );
log.debugf( "Delayed initialization of CDI bean on first use : %s", beanClass.getName() );
final AnnotatedType<T> annotatedType = beanManager.createAnnotatedType( beanClass );
this.injectionTarget = beanManager.createInjectionTarget( annotatedType );
this.creationContext = beanManager.createCreationalContext( null );
this.beanInstance = injectionTarget.produce( creationContext );
injectionTarget.inject( this.beanInstance, creationContext );
injectionTarget.postConstruct( this.beanInstance );
this.initialized = true;
delegate = strategy.createBean( beanManager, beanClass );
}
@Override
public void release() {
if ( !initialized ) {
log.debug( "Skipping release for (delayed) CDI bean [" + beanClass + "] as it was not initialized" );
if ( delegate == null ) {
log.debugf( "Skipping release for (delayed) CDI bean [%s] as it was not initialized", beanClass.getName() );
return;
}
log.debug( "Releasing (delayed) CDI bean : " + beanClass );
log.debugf( "Releasing (delayed) CDI bean : %s", beanClass.getName() );
injectionTarget.preDestroy( beanInstance );
injectionTarget.dispose( beanInstance );
creationContext.release();
initialized = false;
delegate.release();
delegate = null;
}
}
private class NamedManagedBeanImpl<T> implements ManagedBean<T> {
/**
* A named {@link ManagedBean} that is lazily initialized upon the first call to {@link #getBeanInstance()}.
*
* @param <T> The type of bean instances
*
* @see ManagedBeanRegistryCdiExtendedImpl.LazilyInitializedManagedBeanImpl
*/
private class LazilyInitializedNamedManagedBeanImpl<T> implements ManagedBean<T> {
private final String beanName;
private final Class<T> beanContract;
private final CdiLifecycleManagementStrategy strategy;
private boolean initialized = false;
private ManagedBean<T> delegate = null;
private CreationalContext<T> creationContext;
private T beanInstance;
NamedManagedBeanImpl(String beanName, Class<T> beanContract) {
LazilyInitializedNamedManagedBeanImpl(String beanName, Class<T> beanContract, CdiLifecycleManagementStrategy strategy) {
this.beanName = beanName;
this.beanContract = beanContract;
this.strategy = strategy;
}
@Override
@ -126,33 +119,29 @@ public class ManagedBeanRegistryCdiDelayedImpl extends AbstractManagedBeanRegist
@Override
public T getBeanInstance() {
if ( !initialized ) {
if ( delegate == null ) {
initialize();
}
return beanInstance;
return delegate.getBeanInstance();
}
private void initialize() {
final Bean<T> bean = Helper.INSTANCE.getNamedBean( beanName, beanContract, beanManager );
log.debugf( "Delayed initialization of CDI bean on first use : [%s : %s]", beanName, beanContract.getName() );
this.creationContext = beanManager.createCreationalContext( bean );
this.beanInstance = beanContract.cast( beanManager.getReference( bean, beanContract, creationContext ) );
this.initialized = true;
delegate = strategy.createBean( beanManager, beanName, beanContract );
}
@Override
public void release() {
if ( !initialized ) {
if ( delegate == null ) {
log.debugf( "Skipping release for (delayed) CDI bean [%s : %s] as it was not initialized", beanName, beanContract.getName() );
return;
}
log.debugf( "Releasing (delayed) CDI bean [%s : %s]", beanName, beanContract.getName() );
creationContext.release();
initialized = false;
delegate.release();
delegate = null;
}
}

View File

@ -6,11 +6,7 @@
*/
package org.hibernate.resource.beans.internal;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.InjectionTarget;
import org.hibernate.resource.beans.spi.AbstractManagedBeanRegistry;
import org.hibernate.resource.beans.spi.ExtendedBeanManager;
@ -44,12 +40,12 @@ public class ManagedBeanRegistryCdiExtendedImpl
@Override
protected <T> ManagedBean<T> createBean(Class<T> beanClass) {
return new ManagedBeanImpl<>( beanClass );
return new LazilyInitializedManagedBeanImpl<>( beanClass, JpaCdiLifecycleManagementStrategy.INSTANCE );
}
@Override
protected <T> ManagedBean<T> createBean(String beanName, Class<T> beanContract) {
return new NamedManagedBeanImpl<>( beanName, beanContract );
return new LazilyInitializedNamedManagedBeanImpl<>( beanName, beanContract, StandardCdiLifecycleManagementStrategy.INSTANCE );
}
@Override
@ -67,17 +63,24 @@ public class ManagedBeanRegistryCdiExtendedImpl
return usableBeanManager;
}
private class ManagedBeanImpl<T> implements ManagedBean<T> {
/**
* A {@link ManagedBean} that is lazily initialized upon the first call to {@link #getBeanInstance()},
* relying on a {@link CdiLifecycleManagementStrategy} to initialize a delegate.
*
* Note that initialization is forced by the {@link ManagedBeanRegistryCdiExtendedImpl}
* as soon as the bean manager is initialized, see {@link #beanManagerInitialized(BeanManager)}.
*
* @param <T> The type of bean instances
*/
private class LazilyInitializedManagedBeanImpl<T> implements ManagedBean<T> {
private final Class<T> beanClass;
private final CdiLifecycleManagementStrategy strategy;
private boolean initialized = false;
private ManagedBean<T> delegate = null;
private InjectionTarget<T> injectionTarget;
private CreationalContext<T> creationContext;
private T beanInstance;
private ManagedBeanImpl(Class<T> beanClass) {
LazilyInitializedManagedBeanImpl(Class<T> beanClass, CdiLifecycleManagementStrategy strategy) {
this.beanClass = beanClass;
this.strategy = strategy;
}
@Override
@ -87,54 +90,48 @@ public class ManagedBeanRegistryCdiExtendedImpl
@Override
public T getBeanInstance() {
if ( !initialized ) {
if ( delegate == null ) {
initialize();
}
return beanInstance;
return delegate.getBeanInstance();
}
private void initialize() {
final BeanManager beanManager = getUsableBeanManager();
AnnotatedType<T> annotatedType = beanManager.createAnnotatedType( beanClass );
this.injectionTarget = beanManager.createInjectionTarget( annotatedType );
this.creationContext = beanManager.createCreationalContext( null );
this.beanInstance = injectionTarget.produce( creationContext );
injectionTarget.inject( this.beanInstance, creationContext );
injectionTarget.postConstruct( this.beanInstance );
this.initialized = true;
delegate = strategy.createBean( getUsableBeanManager(), beanClass );
}
@Override
public void release() {
if ( !initialized ) {
if ( delegate == null ) {
log.debugf( "Skipping release for (extended) CDI bean [%s] as it was not initialized", beanClass.getName() );
return;
}
log.debugf( "Releasing (extended) CDI bean [%s]", beanClass.getName() );
log.debugf( "Releasing (extended) CDI bean : %s", beanClass.getName() );
injectionTarget.preDestroy( beanInstance );
injectionTarget.dispose( beanInstance );
creationContext.release();
delegate.release();
delegate = null;
}
}
private class NamedManagedBeanImpl<T> implements ManagedBean<T> {
/**
* A named {@link ManagedBean} that is lazily initialized upon the first call to {@link #getBeanInstance()}.
*
* @param <T> The type of bean instances
*
* @see LazilyInitializedManagedBeanImpl
*/
private class LazilyInitializedNamedManagedBeanImpl<T> implements ManagedBean<T> {
private final String beanName;
private final Class<T> beanContract;
private final CdiLifecycleManagementStrategy strategy;
private boolean initialized = false;
private ManagedBean<T> delegate = null;
private CreationalContext<T> creationContext;
private T beanInstance;
public NamedManagedBeanImpl(
String beanName,
Class<T> beanContract) {
LazilyInitializedNamedManagedBeanImpl(String beanName, Class<T> beanContract, CdiLifecycleManagementStrategy strategy) {
this.beanName = beanName;
this.beanContract = beanContract;
this.strategy = strategy;
}
@Override
@ -144,35 +141,28 @@ public class ManagedBeanRegistryCdiExtendedImpl
@Override
public T getBeanInstance() {
if ( !initialized ) {
if ( delegate == null ) {
initialize();
}
return beanInstance;
return delegate.getBeanInstance();
}
private void initialize() {
final BeanManager beanManager = getUsableBeanManager();
final Bean<T> bean = Helper.INSTANCE.getNamedBean( beanName, beanContract, beanManager );
this.creationContext = beanManager.createCreationalContext( bean );
this.beanInstance = beanContract.cast( beanManager.getReference( bean, beanContract, creationContext ) );
this.initialized = true;
delegate = strategy.createBean( getUsableBeanManager(), beanName, beanContract );
}
@Override
public void release() {
if ( !initialized ) {
if ( delegate == null ) {
log.debugf( "Skipping release for (extended) CDI bean [%s : %s] as it was not initialized", beanName, beanContract.getName() );
return;
}
log.debugf( "Releasing (extended) CDI bean [%s : %s]", beanName, beanContract.getName() );
creationContext.release();
initialized = false;
delegate.release();
delegate = null;
}
}
}

View File

@ -6,11 +6,7 @@
*/
package org.hibernate.resource.beans.internal;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.InjectionTarget;
import org.hibernate.resource.beans.spi.AbstractManagedBeanRegistry;
import org.hibernate.resource.beans.spi.ManagedBean;
@ -39,103 +35,11 @@ class ManagedBeanRegistryCdiStandardImpl extends AbstractManagedBeanRegistry {
@Override
protected <T> ManagedBean<T> createBean(Class<T> beanClass) {
return new ManagedBeanImpl<>( beanClass );
return JpaCdiLifecycleManagementStrategy.INSTANCE.createBean( beanManager, beanClass );
}
@Override
protected <T> ManagedBean<T> createBean(String beanName, Class<T> beanContract) {
return new NamedManagedBeanImpl<>( beanName, beanContract );
}
private class ManagedBeanImpl<T> implements ManagedBean<T> {
private final Class<T> beanClass;
private final InjectionTarget<T> injectionTarget;
private boolean initialized;
private final CreationalContext<T> creationContext;
private final T beanInstance;
public ManagedBeanImpl(Class<T> beanClass) {
this.beanClass = beanClass;
AnnotatedType<T> annotatedType = beanManager.createAnnotatedType( beanClass );
this.injectionTarget = beanManager.createInjectionTarget( annotatedType );
this.creationContext = beanManager.createCreationalContext( null );
this.beanInstance = injectionTarget.produce( creationContext );
injectionTarget.inject( this.beanInstance, creationContext );
injectionTarget.postConstruct( this.beanInstance );
}
@Override
public Class<T> getBeanClass() {
return beanClass;
}
@Override
public T getBeanInstance() {
return beanInstance;
}
@Override
public void release() {
if ( !initialized ) {
log.debugf( "Skipping release for (standard) CDI bean [%s] as it was not initialized", beanClass.getName() );
return;
}
log.debugf( "Releasing (standard) CDI bean [%s]", beanClass.getName() );
injectionTarget.preDestroy( beanInstance );
injectionTarget.dispose( beanInstance );
creationContext.release();
}
}
private class NamedManagedBeanImpl<T> implements ManagedBean<T> {
private final String beanName;
private final Class<T> beanContract;
private boolean initialized;
private CreationalContext<T> creationContext;
private T beanInstance;
private NamedManagedBeanImpl(String beanName, Class<T> beanContract) {
this.beanName = beanName;
this.beanContract = beanContract;
final Bean<T> bean = Helper.INSTANCE.getNamedBean( beanName, beanContract, beanManager );
this.creationContext = beanManager.createCreationalContext( bean );
this.beanInstance = beanContract.cast( beanManager.getReference( bean, beanContract, creationContext ) );
this.initialized = true;
}
@Override
public Class<T> getBeanClass() {
return beanContract;
}
@Override
public T getBeanInstance() {
return beanInstance;
}
@Override
public void release() {
if ( !initialized ) {
log.debugf( "Skipping release for (standard) CDI bean [%s : %s] as it was not initialized", beanName, beanContract.getName() );
return;
}
log.debugf( "Releasing (standard) CDI bean [%s : %s]", beanName, beanContract.getName() );
creationContext.release();
initialized = false;
}
return StandardCdiLifecycleManagementStrategy.INSTANCE.createBean( beanManager, beanName, beanContract );
}
}

View File

@ -0,0 +1,75 @@
/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.resource.beans.internal;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import org.hibernate.resource.beans.spi.ManagedBean;
class StandardCdiLifecycleManagementStrategy implements CdiLifecycleManagementStrategy {
static final StandardCdiLifecycleManagementStrategy INSTANCE = new StandardCdiLifecycleManagementStrategy();
private StandardCdiLifecycleManagementStrategy() {
// private constructor, do not use
}
@Override
public <T> ManagedBean<T> createBean(BeanManager beanManager, Class<T> beanClass) {
Bean<T> bean = Helper.INSTANCE.getBean( beanClass, beanManager );
// Pass the bean to createCreationalContext here so that an existing instance can be returned
CreationalContext<T> creationalContext = beanManager.createCreationalContext( bean );
T beanInstance = bean.create( creationalContext );
return new BeanManagerManagedBeanImpl<>( beanClass, creationalContext, beanInstance );
}
@Override
public <T> ManagedBean<T> createBean(BeanManager beanManager, String beanName, Class<T> beanClass) {
Bean<T> bean = Helper.INSTANCE.getNamedBean( beanName, beanClass, beanManager );
// Pass the bean to createCreationalContext here so that an existing instance can be returned
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 final Class<T> beanClass;
private final CreationalContext<T> creationContext;
private final T beanInstance;
private BeanManagerManagedBeanImpl(
Class<T> beanClass,
CreationalContext<T> creationContext, T beanInstance) {
this.beanClass = beanClass;
this.creationContext = creationContext;
this.beanInstance = beanInstance;
}
@Override
public Class<T> getBeanClass() {
return beanClass;
}
@Override
public T getBeanInstance() {
return beanInstance;
}
@Override
public void release() {
creationContext.release();
}
}
}

View File

@ -0,0 +1,53 @@
/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.resource.beans.internal;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.InjectionTarget;
import org.hibernate.resource.beans.spi.ManagedBean;
class UnnamedRegistryScopedManagedBeanImpl<T> implements ManagedBean<T> {
private final Class<T> beanClass;
private final InjectionTarget<T> injectionTarget;
private final CreationalContext<T> creationContext;
private T beanInstance;
UnnamedRegistryScopedManagedBeanImpl(BeanManager beanManager, Class<T> beanClass) {
this.beanClass = beanClass;
final AnnotatedType<T> annotatedType = beanManager.createAnnotatedType( beanClass );
this.injectionTarget = beanManager.createInjectionTarget( annotatedType );
this.creationContext = beanManager.createCreationalContext( null );
this.beanInstance = injectionTarget.produce( creationContext );
injectionTarget.inject( this.beanInstance, creationContext );
injectionTarget.postConstruct( this.beanInstance );
}
@Override
public Class<T> getBeanClass() {
return beanClass;
}
@Override
public T getBeanInstance() {
return beanInstance;
}
@Override
public void release() {
injectionTarget.preDestroy( beanInstance );
injectionTarget.dispose( beanInstance );
creationContext.release();
}
}