DATAJPA-1392 - Optimizations in JpaMetamodelMappingContext(FactoryBean) setup.
We now avoid the eager scanning and addition of JPA managed types to create the JpaMetamodelMappingContext. We also avoid repeated lookups in the Metamodel as we assume the one used for the entity will also be the one that has to be used for all properties of that entity.
This commit is contained in:
@@ -63,7 +63,10 @@ public class JpaMetamodelMappingContext
|
||||
*/
|
||||
@Override
|
||||
protected <T> JpaPersistentEntityImpl<?> createPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
return new JpaPersistentEntityImpl<T>(typeInformation, persistenceProvider);
|
||||
|
||||
Metamodel metamodel = getMetamodelFor(typeInformation.getType());
|
||||
|
||||
return new JpaPersistentEntityImpl<T>(typeInformation, persistenceProvider, metamodel);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -73,14 +76,7 @@ public class JpaMetamodelMappingContext
|
||||
@Override
|
||||
protected JpaPersistentProperty createPersistentProperty(Property property, JpaPersistentEntityImpl<?> owner,
|
||||
SimpleTypeHolder simpleTypeHolder) {
|
||||
|
||||
Metamodel metamodel = getMetamodelFor(owner.getType());
|
||||
|
||||
if (metamodel == null) {
|
||||
throw new IllegalStateException(String.format("Metamodel for %s not available!", owner.getType()));
|
||||
}
|
||||
|
||||
return new JpaPersistentPropertyImpl(metamodel, property, owner, simpleTypeHolder);
|
||||
return new JpaPersistentPropertyImpl(owner.getMetamodel(), property, owner, simpleTypeHolder);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,6 +17,8 @@ package org.springframework.data.jpa.mapping;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import javax.persistence.metamodel.Metamodel;
|
||||
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.jpa.provider.ProxyIdAccessor;
|
||||
import org.springframework.data.mapping.IdentifierAccessor;
|
||||
@@ -43,6 +45,7 @@ class JpaPersistentEntityImpl<T> extends BasicPersistentEntity<T, JpaPersistentP
|
||||
+ javax.persistence.Version.class.getName() + " to trigger optimistic locking correctly!";
|
||||
|
||||
private final ProxyIdAccessor proxyIdAccessor;
|
||||
private final Metamodel metamodel;
|
||||
|
||||
/**
|
||||
* Creates a new {@link JpaPersistentEntityImpl} using the given {@link TypeInformation} and {@link Comparator}.
|
||||
@@ -50,12 +53,13 @@ class JpaPersistentEntityImpl<T> extends BasicPersistentEntity<T, JpaPersistentP
|
||||
* @param information must not be {@literal null}.
|
||||
* @param proxyIdAccessor must not be {@literal null}.
|
||||
*/
|
||||
public JpaPersistentEntityImpl(TypeInformation<T> information, ProxyIdAccessor proxyIdAccessor) {
|
||||
public JpaPersistentEntityImpl(TypeInformation<T> information, ProxyIdAccessor proxyIdAccessor, Metamodel metamodel) {
|
||||
|
||||
super(information, null);
|
||||
|
||||
Assert.notNull(proxyIdAccessor, "ProxyIdAccessor must not be null!");
|
||||
this.proxyIdAccessor = proxyIdAccessor;
|
||||
this.metamodel = metamodel;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -92,6 +96,10 @@ class JpaPersistentEntityImpl<T> extends BasicPersistentEntity<T, JpaPersistentP
|
||||
}
|
||||
}
|
||||
|
||||
Metamodel getMetamodel() {
|
||||
return metamodel;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link IdentifierAccessor} that tries to use a {@link ProxyIdAccessor} for id access to potentially avoid the
|
||||
* initialization of JPA proxies. We're falling back to the default behavior of {@link IdPropertyIdentifierAccessor}
|
||||
@@ -112,8 +120,7 @@ class JpaPersistentEntityImpl<T> extends BasicPersistentEntity<T, JpaPersistentP
|
||||
* @param bean must not be {@literal null}.
|
||||
* @param proxyIdAccessor must not be {@literal null}.
|
||||
*/
|
||||
JpaProxyAwareIdentifierAccessor(JpaPersistentEntity<?> entity, Object bean,
|
||||
ProxyIdAccessor proxyIdAccessor) {
|
||||
JpaProxyAwareIdentifierAccessor(JpaPersistentEntity<?> entity, Object bean, ProxyIdAccessor proxyIdAccessor) {
|
||||
|
||||
super(entity, bean);
|
||||
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
package org.springframework.data.jpa.repository.config;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.metamodel.ManagedType;
|
||||
import javax.persistence.metamodel.Metamodel;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
@@ -31,6 +31,7 @@ import org.springframework.beans.factory.config.AbstractFactoryBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext;
|
||||
import org.springframework.data.util.StreamUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
@@ -43,6 +44,8 @@ import org.springframework.lang.Nullable;
|
||||
class JpaMetamodelMappingContextFactoryBean extends AbstractFactoryBean<JpaMetamodelMappingContext>
|
||||
implements ApplicationContextAware {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JpaMetamodelMappingContextFactoryBean.class);
|
||||
|
||||
private @Nullable ListableBeanFactory beanFactory;
|
||||
|
||||
/*
|
||||
@@ -70,25 +73,17 @@ class JpaMetamodelMappingContextFactoryBean extends AbstractFactoryBean<JpaMetam
|
||||
@Override
|
||||
protected JpaMetamodelMappingContext createInstance() throws Exception {
|
||||
|
||||
Set<Metamodel> models = getMetamodels();
|
||||
Set<Class<?>> entitySources = new HashSet<Class<?>>();
|
||||
|
||||
for (Metamodel metamodel : models) {
|
||||
|
||||
for (ManagedType<?> type : metamodel.getManagedTypes()) {
|
||||
|
||||
Class<?> javaType = type.getJavaType();
|
||||
|
||||
if (javaType != null) {
|
||||
entitySources.add(javaType);
|
||||
}
|
||||
}
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Initializing JpaMetamodelMappingContext…");
|
||||
}
|
||||
|
||||
JpaMetamodelMappingContext context = new JpaMetamodelMappingContext(models);
|
||||
context.setInitialEntitySet(entitySources);
|
||||
JpaMetamodelMappingContext context = new JpaMetamodelMappingContext(getMetamodels());
|
||||
context.initialize();
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Finished initializing JpaMetamodelMappingContext!");
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
@@ -105,12 +100,9 @@ class JpaMetamodelMappingContextFactoryBean extends AbstractFactoryBean<JpaMetam
|
||||
|
||||
Collection<EntityManagerFactory> factories = BeanFactoryUtils
|
||||
.beansOfTypeIncludingAncestors(beanFactory, EntityManagerFactory.class).values();
|
||||
Set<Metamodel> metamodels = new HashSet<Metamodel>(factories.size());
|
||||
|
||||
for (EntityManagerFactory emf : factories) {
|
||||
metamodels.add(emf.getMetamodel());
|
||||
}
|
||||
|
||||
return metamodels;
|
||||
return factories.stream() //
|
||||
.map(EntityManagerFactory::getMetamodel) //
|
||||
.collect(StreamUtils.toUnmodifiableSet());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,16 +16,15 @@
|
||||
package org.springframework.data.jpa.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.metamodel.EntityType;
|
||||
import javax.persistence.metamodel.ManagedType;
|
||||
import javax.persistence.metamodel.Metamodel;
|
||||
import javax.persistence.metamodel.SingularAttribute;
|
||||
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.StreamUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -38,7 +37,7 @@ public class JpaMetamodel {
|
||||
|
||||
private final Metamodel metamodel;
|
||||
|
||||
private Optional<Collection<Class<?>>> managedTypes = Optional.empty();
|
||||
private Lazy<Collection<Class<?>>> managedTypes;
|
||||
|
||||
/**
|
||||
* Creates a new {@link JpaMetamodel} for the given JPA {@link Metamodel}.
|
||||
@@ -50,6 +49,10 @@ public class JpaMetamodel {
|
||||
Assert.notNull(metamodel, "Metamodel must not be null!");
|
||||
|
||||
this.metamodel = metamodel;
|
||||
this.managedTypes = Lazy.of(() -> metamodel.getManagedTypes().stream() //
|
||||
.map(ManagedType::getJavaType) //
|
||||
.filter(it -> it != null) //
|
||||
.collect(StreamUtils.toUnmodifiableSet()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,7 +65,7 @@ public class JpaMetamodel {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
|
||||
return getManagedTypes().contains(type);
|
||||
return managedTypes.get().contains(type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,35 +87,6 @@ public class JpaMetamodel {
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all types managed by the backing {@link Metamodel}. Skips {@link ManagedType} instances that return
|
||||
* {@literal null} for calls to {@link ManagedType#getJavaType()}.
|
||||
*
|
||||
* @return all managed types.
|
||||
* @see <a href="https://hibernate.atlassian.net/browse/HHH-10968">HHH-10968</a>
|
||||
*/
|
||||
private Collection<Class<?>> getManagedTypes() {
|
||||
|
||||
if (!managedTypes.isPresent()) {
|
||||
|
||||
Set<ManagedType<?>> managedTypes = metamodel.getManagedTypes();
|
||||
Set<Class<?>> types = new HashSet<Class<?>>(managedTypes.size());
|
||||
|
||||
for (ManagedType<?> managedType : metamodel.getManagedTypes()) {
|
||||
|
||||
Class<?> type = managedType.getJavaType();
|
||||
|
||||
if (type != null) {
|
||||
types.add(type);
|
||||
}
|
||||
}
|
||||
|
||||
this.managedTypes = Optional.of(Collections.unmodifiableSet(types));
|
||||
}
|
||||
|
||||
return this.managedTypes.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link SingularAttribute} representing the identifier of the given {@link EntityType} if it contains a
|
||||
* singular one.
|
||||
|
||||
@@ -22,10 +22,8 @@ import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.metamodel.ManagedType;
|
||||
import javax.persistence.metamodel.Metamodel;
|
||||
|
||||
import org.junit.Rule;
|
||||
@@ -100,13 +98,9 @@ public class JpaRepositoryConfigExtensionUnitTests {
|
||||
ApplicationContext context = mock(ApplicationContext.class);
|
||||
EntityManagerFactory emf = mock(EntityManagerFactory.class);
|
||||
Metamodel metamodel = mock(Metamodel.class);
|
||||
ManagedType<?> managedType = mock(ManagedType.class);
|
||||
|
||||
Set<ManagedType<?>> managedTypes = Collections.<ManagedType<?>> singleton(managedType);
|
||||
|
||||
when(context.getBeansOfType(EntityManagerFactory.class)).thenReturn(Collections.singletonMap("emf", emf));
|
||||
when(emf.getMetamodel()).thenReturn(metamodel);
|
||||
when(metamodel.getManagedTypes()).thenReturn(managedTypes);
|
||||
|
||||
JpaMetamodelMappingContextFactoryBean factoryBean = new JpaMetamodelMappingContextFactoryBean();
|
||||
factoryBean.setApplicationContext(context);
|
||||
|
||||
Reference in New Issue
Block a user