HHH-13015 Optimise loading of EntityCopyObserver implementation

This commit is contained in:
Sanne Grinovero 2018-10-05 15:57:49 +01:00 committed by Sanne Grinovero
parent 415fcfd048
commit cced0ad568
8 changed files with 144 additions and 52 deletions

View File

@ -166,7 +166,6 @@ public class StrategySelectorBuilder {
addJtaPlatforms( strategySelector );
addTransactionCoordinatorBuilders( strategySelector );
addMultiTableBulkIdStrategies( strategySelector );
addEntityCopyObserverStrategies( strategySelector );
addImplicitNamingStrategies( strategySelector );
addCacheKeysFactories( strategySelector );
@ -429,24 +428,6 @@ public class StrategySelectorBuilder {
);
}
private void addEntityCopyObserverStrategies(StrategySelectorImpl strategySelector) {
strategySelector.registerStrategyImplementor(
EntityCopyObserver.class,
EntityCopyNotAllowedObserver.SHORT_NAME,
EntityCopyNotAllowedObserver.class
);
strategySelector.registerStrategyImplementor(
EntityCopyObserver.class,
EntityCopyAllowedObserver.SHORT_NAME,
EntityCopyAllowedObserver.class
);
strategySelector.registerStrategyImplementor(
EntityCopyObserver.class,
EntityCopyAllowedLoggedObserver.SHORT_NAME,
EntityCopyAllowedLoggedObserver.class
);
}
private void addImplicitNamingStrategies(StrategySelectorImpl strategySelector) {
strategySelector.registerStrategyImplementor(
ImplicitNamingStrategy.class,

View File

@ -14,9 +14,6 @@ import org.hibernate.HibernateException;
import org.hibernate.ObjectDeletedException;
import org.hibernate.StaleObjectStateException;
import org.hibernate.WrongClassException;
import org.hibernate.boot.registry.selector.spi.StrategySelector;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.internal.Cascade;
import org.hibernate.engine.internal.CascadePoint;
import org.hibernate.engine.spi.CascadingAction;
@ -27,6 +24,7 @@ import org.hibernate.engine.spi.SelfDirtinessTracker;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.event.spi.EntityCopyObserver;
import org.hibernate.event.spi.EntityCopyObserverFactory;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.MergeEvent;
import org.hibernate.event.spi.MergeEventListener;
@ -48,8 +46,6 @@ import org.hibernate.type.TypeHelper;
public class DefaultMergeEventListener extends AbstractSaveEventListener implements MergeEventListener {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( DefaultMergeEventListener.class );
private String entityCopyObserverStrategy;
@Override
protected Map getMergeMap(Object anything) {
return ( (MergeContext) anything ).invertMap();
@ -77,23 +73,8 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener impleme
private EntityCopyObserver createEntityCopyObserver(SessionFactoryImplementor sessionFactory) {
final ServiceRegistry serviceRegistry = sessionFactory.getServiceRegistry();
if ( entityCopyObserverStrategy == null ) {
final ConfigurationService configurationService
= serviceRegistry.getService( ConfigurationService.class );
entityCopyObserverStrategy = configurationService.getSetting(
AvailableSettings.MERGE_ENTITY_COPY_OBSERVER,
new ConfigurationService.Converter<String>() {
@Override
public String convert(Object value) {
return value.toString();
}
},
EntityCopyNotAllowedObserver.SHORT_NAME
);
LOG.debugf( "EntityCopyObserver strategy: %s", entityCopyObserverStrategy );
}
final StrategySelector strategySelector = serviceRegistry.getService( StrategySelector.class );
return strategySelector.resolveStrategy( EntityCopyObserver.class, entityCopyObserverStrategy );
final EntityCopyObserverFactory configurationService = serviceRegistry.getService( EntityCopyObserverFactory.class );
return configurationService.createEntityCopyObserver();
}
/**

View File

@ -11,6 +11,8 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.hibernate.event.spi.EntityCopyObserver;
import org.hibernate.event.spi.EntityCopyObserverFactory;
import org.hibernate.event.spi.EventSource;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
@ -24,9 +26,12 @@ import org.hibernate.pretty.MessageHelper;
*
* @author Gail Badner
*/
public class EntityCopyAllowedLoggedObserver extends EntityCopyAllowedObserver {
public final class EntityCopyAllowedLoggedObserver implements EntityCopyObserver {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( EntityCopyAllowedLoggedObserver.class );
public static final EntityCopyObserverFactory FACTORY_OF_SELF = () -> new EntityCopyAllowedLoggedObserver();
public static final String SHORT_NAME = "log";
// Tracks the number of entity copies per entity name.
@ -39,13 +44,8 @@ public class EntityCopyAllowedLoggedObserver extends EntityCopyAllowedObserver {
// key is the managed entity;
// value is the set of representations being merged corresponding to the same managed result.
/**
* Indicates if DEBUG logging is enabled.
*
* @return true, if DEBUG logging is enabled.
*/
public static boolean isDebugLoggingEnabled() {
return LOG.isDebugEnabled();
private EntityCopyAllowedLoggedObserver() {
//Not to be constructed directly; use FACTORY_OF_SELF.
}
@Override

View File

@ -7,6 +7,7 @@
package org.hibernate.event.internal;
import org.hibernate.event.spi.EntityCopyObserver;
import org.hibernate.event.spi.EntityCopyObserverFactory;
import org.hibernate.event.spi.EventSource;
/**
@ -15,9 +16,17 @@ import org.hibernate.event.spi.EventSource;
*
* @author Gail Badner
*/
public class EntityCopyAllowedObserver implements EntityCopyObserver {
public final class EntityCopyAllowedObserver implements EntityCopyObserver {
public static final String SHORT_NAME = "allow";
private static final EntityCopyObserver INSTANCE = new EntityCopyAllowedObserver();
//This implementation of EntityCopyObserver is stateless, so no need to create multiple copies:
public static final EntityCopyObserverFactory FACTORY_OF_SELF = () -> INSTANCE;
private EntityCopyAllowedObserver() {
//Not to be constructed; use INSTANCE.
}
@Override
public void entityCopyDetected(
@ -32,9 +41,9 @@ public class EntityCopyAllowedObserver implements EntityCopyObserver {
// do nothing.
}
@Override
public void topLevelMergeComplete(EventSource session) {
// do nothing.
}
}

View File

@ -8,15 +8,23 @@ package org.hibernate.event.internal;
import org.hibernate.AssertionFailure;
import org.hibernate.event.spi.EntityCopyObserver;
import org.hibernate.event.spi.EntityCopyObserverFactory;
import org.hibernate.event.spi.EventSource;
import org.hibernate.pretty.MessageHelper;
/**
* @author Gail Badner
*/
public class EntityCopyNotAllowedObserver implements EntityCopyObserver {
public final class EntityCopyNotAllowedObserver implements EntityCopyObserver {
public static final String SHORT_NAME = "disallow";
private static final EntityCopyNotAllowedObserver INSTANCE = new EntityCopyNotAllowedObserver();
//This implementation of EntityCopyObserver is stateless, so no need to create multiple copies:
public static final EntityCopyObserverFactory FACTORY_OF_SELF = () -> INSTANCE;
private EntityCopyNotAllowedObserver() {
//Not to be constructed; use INSTANCE.
}
@Override
public void entityCopyDetected(

View File

@ -0,0 +1,97 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* 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.event.internal;
import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.boot.registry.StandardServiceInitiator;
import org.hibernate.boot.registry.selector.spi.StrategySelector;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.event.spi.EntityCopyObserver;
import org.hibernate.event.spi.EntityCopyObserverFactory;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.service.spi.ServiceRegistryImplementor;
/**
* Looks for the configuration property {@link AvailableSettings#MERGE_ENTITY_COPY_OBSERVER} and registers
* the matching {@link EntityCopyObserverFactory} based on the configuration value.
* <p>
* For known implementations some optimisations are possible, such as reusing a singleton for the stateless
* implementations. When a user plugs in a custom {@link EntityCopyObserver} we take a defensive approach.
* </p>
*/
public class EntityCopyObserverFactoryInitiator implements StandardServiceInitiator<EntityCopyObserverFactory> {
public static final EntityCopyObserverFactoryInitiator INSTANCE = new EntityCopyObserverFactoryInitiator();
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( EntityCopyObserverFactoryInitiator.class );
@Override
public EntityCopyObserverFactory initiateService(final Map configurationValues, final ServiceRegistryImplementor registry) {
final Object value = getConfigurationValue( configurationValues );
if ( value.equals( EntityCopyNotAllowedObserver.SHORT_NAME ) || value.equals( EntityCopyNotAllowedObserver.class.getName() ) ) {
LOG.debugf( "Configured EntityCopyObserver strategy: " + EntityCopyNotAllowedObserver.SHORT_NAME );
return EntityCopyNotAllowedObserver.FACTORY_OF_SELF;
}
else if ( value.equals( EntityCopyAllowedObserver.SHORT_NAME ) || value.equals( EntityCopyAllowedObserver.class.getName() ) ) {
LOG.debugf( "Configured EntityCopyObserver strategy: " + EntityCopyAllowedObserver.SHORT_NAME );
return EntityCopyAllowedObserver.FACTORY_OF_SELF;
}
else if ( value.equals( EntityCopyAllowedLoggedObserver.SHORT_NAME ) || value.equals( EntityCopyAllowedLoggedObserver.class.getName() ) ) {
LOG.debugf( "Configured EntityCopyObserver strategy: " + EntityCopyAllowedLoggedObserver.SHORT_NAME );
return EntityCopyAllowedLoggedObserver.FACTORY_OF_SELF;
}
else {
//We load an "example instance" just to get its Class;
//this might look excessive, but it also happens to test eagerly (at boot) that we can actually construct these
//and that they are indeed of the right type.
EntityCopyObserver exampleInstance = registry.getService( StrategySelector.class ).resolveStrategy( EntityCopyObserver.class, value );
Class observerType = exampleInstance.getClass();
LOG.debugf( "Configured EntityCopyObserver is a custom implementation of type " + observerType.getName() );
return new EntityObserversFactoryFromClass( observerType );
}
}
private Object getConfigurationValue(final Map configurationValues) {
final Object o = configurationValues.get( AvailableSettings.MERGE_ENTITY_COPY_OBSERVER );
if ( o == null ) {
return EntityCopyNotAllowedObserver.SHORT_NAME; //default
}
else if ( o instanceof String ) {
return o.toString().trim();
}
else {
return o;
}
}
@Override
public Class<EntityCopyObserverFactory> getServiceInitiated() {
return EntityCopyObserverFactory.class;
}
private static class EntityObserversFactoryFromClass implements EntityCopyObserverFactory {
private final Class value;
public EntityObserversFactoryFromClass(Class value) {
this.value = value;
}
@Override
public EntityCopyObserver createEntityCopyObserver() {
try {
return (EntityCopyObserver) value.newInstance();
}
catch (Exception e) {
throw new HibernateException( "Could not instantiate class of type " + value.getName() );
}
}
}
}

View File

@ -0,0 +1,14 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* 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.event.spi;
import org.hibernate.service.Service;
@FunctionalInterface
public interface EntityCopyObserverFactory extends Service {
EntityCopyObserver createEntityCopyObserver();
}

View File

@ -25,6 +25,7 @@ import org.hibernate.engine.jdbc.internal.JdbcServicesInitiator;
import org.hibernate.engine.jndi.internal.JndiServiceInitiator;
import org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator;
import org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformResolverInitiator;
import org.hibernate.event.internal.EntityCopyObserverFactoryInitiator;
import org.hibernate.hql.internal.QueryTranslatorFactoryInitiator;
import org.hibernate.id.factory.internal.MutableIdentifierGeneratorFactoryInitiator;
import org.hibernate.jmx.internal.JmxServiceInitiator;
@ -86,6 +87,7 @@ public final class StandardServiceInitiators {
serviceInitiators.add( TransactionCoordinatorBuilderInitiator.INSTANCE );
serviceInitiators.add( ManagedBeanRegistryInitiator.INSTANCE );
serviceInitiators.add( EntityCopyObserverFactoryInitiator.INSTANCE );
serviceInitiators.trimToSize();