Browse Source

Introduce interface cache for EntityManager and Query types

We now reuse interfaces for EntityManager and Query classes that
are proxied through ExtendedEntityManagerCreator and SharedEntityManagerCreator.

These caches prevent excessive object allocations through
ClassUtils.getAllInterfacesForClass(…) and
ClassUtils.getAllInterfacesForClassAsSet(…).
pull/23401/head
Mark Paluch 5 years ago committed by Juergen Hoeller
parent
commit
1890e04df1
  1. 26
      spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java
  2. 7
      spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java

26
spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java

@ -43,6 +43,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager @@ -43,6 +43,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
/**
* Delegate for creating a variety of {@link javax.persistence.EntityManager}
@ -65,6 +66,7 @@ import org.springframework.util.CollectionUtils; @@ -65,6 +66,7 @@ import org.springframework.util.CollectionUtils;
*
* @author Juergen Hoeller
* @author Rod Johnson
* @author Mark Paluch
* @since 2.0
* @see javax.persistence.EntityManagerFactory#createEntityManager()
* @see javax.persistence.PersistenceContextType#EXTENDED
@ -73,6 +75,8 @@ import org.springframework.util.CollectionUtils; @@ -73,6 +75,8 @@ import org.springframework.util.CollectionUtils;
*/
public abstract class ExtendedEntityManagerCreator {
private static final Map<Class<?>, Class[]> CACHED_ENTITY_MANAGER_INTERFACES = new ConcurrentReferenceHashMap<>();
/**
* Create an application-managed extended EntityManager proxy.
* @param rawEntityManager the raw EntityManager to decorate
@ -222,17 +226,29 @@ public abstract class ExtendedEntityManagerCreator { @@ -222,17 +226,29 @@ public abstract class ExtendedEntityManagerCreator {
boolean containerManaged, boolean synchronizedWithTransaction) {
Assert.notNull(rawEm, "EntityManager must not be null");
Set<Class<?>> ifcs = new LinkedHashSet<>();
Class[] interfaces;
if (emIfc != null) {
ifcs.add(emIfc);
interfaces = CACHED_ENTITY_MANAGER_INTERFACES.computeIfAbsent(emIfc, key -> {
Set<Class<?>> ifcs = new LinkedHashSet<>();
ifcs.add(key);
ifcs.add(EntityManagerProxy.class);
return ClassUtils.toClassArray(ifcs);
});
}
else {
ifcs.addAll(ClassUtils.getAllInterfacesForClassAsSet(rawEm.getClass(), cl));
interfaces = CACHED_ENTITY_MANAGER_INTERFACES.computeIfAbsent(rawEm.getClass(), key -> {
Set<Class<?>> ifcs = new LinkedHashSet<>();
ifcs.addAll(ClassUtils
.getAllInterfacesForClassAsSet(key, cl));
ifcs.add(EntityManagerProxy.class);
return ClassUtils.toClassArray(ifcs);
});
}
ifcs.add(EntityManagerProxy.class);
return (EntityManager) Proxy.newProxyInstance(
(cl != null ? cl : ExtendedEntityManagerCreator.class.getClassLoader()),
ClassUtils.toClassArray(ifcs),
interfaces,
new ExtendedEntityManagerInvocationHandler(
rawEm, exceptionTranslator, jta, containerManaged, synchronizedWithTransaction));
}

7
spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java

@ -41,6 +41,7 @@ import org.springframework.lang.Nullable; @@ -41,6 +41,7 @@ import org.springframework.lang.Nullable;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
/**
* Delegate for creating a shareable JPA {@link javax.persistence.EntityManager}
@ -59,6 +60,7 @@ import org.springframework.util.CollectionUtils; @@ -59,6 +60,7 @@ import org.springframework.util.CollectionUtils;
* @author Juergen Hoeller
* @author Rod Johnson
* @author Oliver Gierke
* @author Mark Paluch
* @since 2.0
* @see javax.persistence.PersistenceContext
* @see javax.persistence.PersistenceContextType#TRANSACTION
@ -73,6 +75,8 @@ public abstract class SharedEntityManagerCreator { @@ -73,6 +75,8 @@ public abstract class SharedEntityManagerCreator {
private static final Set<String> queryTerminatingMethods = new HashSet<>(8);
private static final Map<Class<?>, Class[]> CACHED_QUERY_INTERFACES = new ConcurrentReferenceHashMap<>();
static {
transactionRequiringMethods.add("joinTransaction");
transactionRequiringMethods.add("flush");
@ -310,7 +314,8 @@ public abstract class SharedEntityManagerCreator { @@ -310,7 +314,8 @@ public abstract class SharedEntityManagerCreator {
if (result instanceof Query) {
Query query = (Query) result;
if (isNewEm) {
Class<?>[] ifcs = ClassUtils.getAllInterfacesForClass(query.getClass(), this.proxyClassLoader);
Class<?>[] ifcs = CACHED_QUERY_INTERFACES.computeIfAbsent(query.getClass(), key ->
ClassUtils.getAllInterfacesForClass(key, this.proxyClassLoader));
result = Proxy.newProxyInstance(this.proxyClassLoader, ifcs,
new DeferredQueryInvocationHandler(query, target));
isNewEm = false;

Loading…
Cancel
Save