Skip to content

Commit 1890e04

Browse files
mp911dejhoeller
authored andcommitted
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(…).
1 parent 96ea3a8 commit 1890e04

File tree

2 files changed

+27
-6
lines changed

2 files changed

+27
-6
lines changed

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

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.springframework.util.Assert;
4444
import org.springframework.util.ClassUtils;
4545
import org.springframework.util.CollectionUtils;
46+
import org.springframework.util.ConcurrentReferenceHashMap;
4647

4748
/**
4849
* Delegate for creating a variety of {@link javax.persistence.EntityManager}
@@ -65,6 +66,7 @@
6566
*
6667
* @author Juergen Hoeller
6768
* @author Rod Johnson
69+
* @author Mark Paluch
6870
* @since 2.0
6971
* @see javax.persistence.EntityManagerFactory#createEntityManager()
7072
* @see javax.persistence.PersistenceContextType#EXTENDED
@@ -73,6 +75,8 @@
7375
*/
7476
public abstract class ExtendedEntityManagerCreator {
7577

78+
private static final Map<Class<?>, Class[]> CACHED_ENTITY_MANAGER_INTERFACES = new ConcurrentReferenceHashMap<>();
79+
7680
/**
7781
* Create an application-managed extended EntityManager proxy.
7882
* @param rawEntityManager the raw EntityManager to decorate
@@ -222,17 +226,29 @@ private static EntityManager createProxy(
222226
boolean containerManaged, boolean synchronizedWithTransaction) {
223227

224228
Assert.notNull(rawEm, "EntityManager must not be null");
225-
Set<Class<?>> ifcs = new LinkedHashSet<>();
229+
Class[] interfaces;
230+
226231
if (emIfc != null) {
227-
ifcs.add(emIfc);
232+
interfaces = CACHED_ENTITY_MANAGER_INTERFACES.computeIfAbsent(emIfc, key -> {
233+
Set<Class<?>> ifcs = new LinkedHashSet<>();
234+
ifcs.add(key);
235+
ifcs.add(EntityManagerProxy.class);
236+
return ClassUtils.toClassArray(ifcs);
237+
});
228238
}
229239
else {
230-
ifcs.addAll(ClassUtils.getAllInterfacesForClassAsSet(rawEm.getClass(), cl));
240+
interfaces = CACHED_ENTITY_MANAGER_INTERFACES.computeIfAbsent(rawEm.getClass(), key -> {
241+
Set<Class<?>> ifcs = new LinkedHashSet<>();
242+
ifcs.addAll(ClassUtils
243+
.getAllInterfacesForClassAsSet(key, cl));
244+
ifcs.add(EntityManagerProxy.class);
245+
return ClassUtils.toClassArray(ifcs);
246+
});
231247
}
232-
ifcs.add(EntityManagerProxy.class);
248+
233249
return (EntityManager) Proxy.newProxyInstance(
234250
(cl != null ? cl : ExtendedEntityManagerCreator.class.getClassLoader()),
235-
ClassUtils.toClassArray(ifcs),
251+
interfaces,
236252
new ExtendedEntityManagerInvocationHandler(
237253
rawEm, exceptionTranslator, jta, containerManaged, synchronizedWithTransaction));
238254
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.springframework.transaction.support.TransactionSynchronizationManager;
4242
import org.springframework.util.ClassUtils;
4343
import org.springframework.util.CollectionUtils;
44+
import org.springframework.util.ConcurrentReferenceHashMap;
4445

4546
/**
4647
* Delegate for creating a shareable JPA {@link javax.persistence.EntityManager}
@@ -59,6 +60,7 @@
5960
* @author Juergen Hoeller
6061
* @author Rod Johnson
6162
* @author Oliver Gierke
63+
* @author Mark Paluch
6264
* @since 2.0
6365
* @see javax.persistence.PersistenceContext
6466
* @see javax.persistence.PersistenceContextType#TRANSACTION
@@ -73,6 +75,8 @@ public abstract class SharedEntityManagerCreator {
7375

7476
private static final Set<String> queryTerminatingMethods = new HashSet<>(8);
7577

78+
private static final Map<Class<?>, Class[]> CACHED_QUERY_INTERFACES = new ConcurrentReferenceHashMap<>();
79+
7680
static {
7781
transactionRequiringMethods.add("joinTransaction");
7882
transactionRequiringMethods.add("flush");
@@ -310,7 +314,8 @@ else if (transactionRequiringMethods.contains(method.getName())) {
310314
if (result instanceof Query) {
311315
Query query = (Query) result;
312316
if (isNewEm) {
313-
Class<?>[] ifcs = ClassUtils.getAllInterfacesForClass(query.getClass(), this.proxyClassLoader);
317+
Class<?>[] ifcs = CACHED_QUERY_INTERFACES.computeIfAbsent(query.getClass(), key ->
318+
ClassUtils.getAllInterfacesForClass(key, this.proxyClassLoader));
314319
result = Proxy.newProxyInstance(this.proxyClassLoader, ifcs,
315320
new DeferredQueryInvocationHandler(query, target));
316321
isNewEm = false;

0 commit comments

Comments
 (0)