diff --git a/src/main/java/org/springframework/data/convert/ReflectionEntityInstantiator.java b/src/main/java/org/springframework/data/convert/ReflectionEntityInstantiator.java index df27287d3..6c53f0f33 100644 --- a/src/main/java/org/springframework/data/convert/ReflectionEntityInstantiator.java +++ b/src/main/java/org/springframework/data/convert/ReflectionEntityInstantiator.java @@ -16,6 +16,7 @@ package org.springframework.data.convert; import java.lang.reflect.Array; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -39,6 +40,19 @@ public enum ReflectionEntityInstantiator implements EntityInstantiator { INSTANCE; + private final int ARG_CACHE_SIZE = 100; + + private final ThreadLocal objectPool = ThreadLocal.withInitial(() -> { + + Object[][] cached = new Object[ARG_CACHE_SIZE][]; + + for (int i = 0; i < ARG_CACHE_SIZE; i++) { + cached[i] = new Object[i]; + } + + return cached; + }); + @SuppressWarnings("unchecked") public , P extends PersistentProperty

> T createInstance(E entity, ParameterValueProvider

provider) { @@ -64,8 +78,9 @@ public enum ReflectionEntityInstantiator implements EntityInstantiator { throw new MappingInstantiationException(entity, Collections.emptyList(), e); } } + int parameterCount = constructor.getConstructor().getParameterCount(); - Object[] params = new Object[constructor.getConstructor().getParameterCount()]; + Object[] params = parameterCount < ARG_CACHE_SIZE ? objectPool.get()[parameterCount] : new Object[parameterCount]; int i = 0; for (Parameter parameter : constructor.getParameters()) { params[i++] = provider.getParameterValue(parameter); @@ -74,7 +89,9 @@ public enum ReflectionEntityInstantiator implements EntityInstantiator { try { return BeanUtils.instantiateClass(constructor.getConstructor(), params); } catch (BeanInstantiationException e) { - throw new MappingInstantiationException(entity, Arrays.asList(params), e); + throw new MappingInstantiationException(entity, new ArrayList<>(Arrays.asList(params)), e); + } finally { + Arrays.fill(params, null); } } } diff --git a/src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java b/src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java index d2ac59b91..e588910dd 100644 --- a/src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java +++ b/src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java @@ -66,9 +66,12 @@ import org.springframework.util.ReflectionUtils; */ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccessorFactory { + // Pooling of parameter arrays to prevent excessive object allocation. + private final ThreadLocal argumentCache = ThreadLocal.withInitial(() -> new Object[1]); + + private volatile Map, Constructor> constructorMap = new HashMap<>(32); private volatile Map, Class> propertyAccessorClasses = new HashMap<>( 32); - private volatile Map, Constructor> constructorMap = new HashMap<>(32); /* * (non-Javadoc) @@ -77,15 +80,28 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert @Override public PersistentPropertyAccessor getPropertyAccessor(PersistentEntity entity, Object bean) { - final Class propertyAccessorClass = propertyAccessorClasses.computeIfAbsent( - entity.getTypeInformation(), k -> potentiallyCreateAndRegisterPersistentPropertyAccessorClass(entity)); + Constructor constructor = constructorMap.get(entity); + + if (constructor == null) { + + Class accessorClass = potentiallyCreateAndRegisterPersistentPropertyAccessorClass( + entity); + constructor = accessorClass.getConstructors()[0]; + + Map, Constructor> constructorMap = new HashMap<>(this.constructorMap); + constructorMap.put(entity, constructor); + this.constructorMap = constructorMap; + } + + Object[] args = argumentCache.get(); + args[0] = bean; try { - - return (PersistentPropertyAccessor) constructorMap - .computeIfAbsent(propertyAccessorClass, k -> propertyAccessorClass.getConstructors()[0]).newInstance(bean); + return (PersistentPropertyAccessor) constructor.newInstance(args); } catch (Exception e) { throw new IllegalArgumentException(String.format("Cannot create persistent property accessor for %s", entity), e); + } finally { + args[0] = null; } }