21
21
import java .lang .reflect .Modifier ;
22
22
import java .security .AccessController ;
23
23
import java .security .PrivilegedAction ;
24
- import java .util .ArrayList ;
25
24
import java .util .Arrays ;
26
25
import java .util .HashMap ;
27
- import java .util .List ;
28
26
import java .util .Map ;
29
27
30
28
import org .springframework .asm .ClassWriter ;
57
55
*/
58
56
public class ClassGeneratingEntityInstantiator implements EntityInstantiator {
59
57
58
+ private static final int ARG_CACHE_SIZE = 100 ;
59
+
60
+ private static final ThreadLocal <Object [][]> OBJECT_POOL = ThreadLocal .withInitial (() -> {
61
+
62
+ Object [][] cached = new Object [ARG_CACHE_SIZE ][];
63
+
64
+ for (int i = 0 ; i < ARG_CACHE_SIZE ; i ++) {
65
+ cached [i ] = new Object [i ];
66
+ }
67
+
68
+ return cached ;
69
+ });
70
+
60
71
private final ObjectInstantiatorClassGenerator generator ;
61
72
62
73
private volatile Map <TypeInformation <?>, EntityInstantiator > entityInstantiators = new HashMap <>(32 );
@@ -120,12 +131,20 @@ private EntityInstantiator createEntityInstantiator(PersistentEntity<?, ?> entit
120
131
}
121
132
122
133
try {
123
- return new EntityInstantiatorAdapter ( createObjectInstantiator ( entity ) );
134
+ return doCreateEntityInstantiator ( entity );
124
135
} catch (Throwable ex ) {
125
136
return ReflectionEntityInstantiator .INSTANCE ;
126
137
}
127
138
}
128
139
140
+ /**
141
+ * @param entity
142
+ * @return
143
+ */
144
+ protected EntityInstantiator doCreateEntityInstantiator (PersistentEntity <?, ?> entity ) {
145
+ return new EntityInstantiatorAdapter (createObjectInstantiator (entity , entity .getPersistenceConstructor ()));
146
+ }
147
+
129
148
/**
130
149
* @param entity
131
150
* @return
@@ -151,17 +170,46 @@ private boolean shouldUseReflectionEntityInstantiator(PersistentEntity<?, ?> ent
151
170
}
152
171
153
172
/**
154
- * Creates a dynamically generated {@link ObjectInstantiator} for the given {@link PersistentEntity}. There will
155
- * always be exactly one {@link ObjectInstantiator} instance per {@link PersistentEntity}.
156
- * <p>
173
+ * Allocates an object array for instance creation. This method uses the argument array cache if possible.
174
+ *
175
+ * @param argumentCount
176
+ * @return
177
+ * @since 2.0
178
+ * @see #ARG_CACHE_SIZE
179
+ */
180
+ static Object [] allocateArguments (int argumentCount ) {
181
+ return argumentCount < ARG_CACHE_SIZE ? OBJECT_POOL .get ()[argumentCount ] : new Object [argumentCount ];
182
+ }
183
+
184
+ /**
185
+ * Deallocates an object array used for instance creation. Parameters are cleared if the array was cached.
186
+ *
187
+ * @param argumentCount
188
+ * @return
189
+ * @since 2.0
190
+ * @see #ARG_CACHE_SIZE
191
+ */
192
+ static void deallocateArguments (Object [] params ) {
193
+
194
+ if (params .length != 0 && params .length < ARG_CACHE_SIZE ) {
195
+ Arrays .fill (params , null );
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Creates a dynamically generated {@link ObjectInstantiator} for the given {@link PersistentEntity} and
201
+ * {@link PreferredConstructor}. There will always be exactly one {@link ObjectInstantiator} instance per
202
+ * {@link PersistentEntity}.
157
203
*
158
204
* @param entity
205
+ * @param constructor
159
206
* @return
160
207
*/
161
- private ObjectInstantiator createObjectInstantiator (PersistentEntity <?, ?> entity ) {
208
+ ObjectInstantiator createObjectInstantiator (PersistentEntity <?, ?> entity ,
209
+ @ Nullable PreferredConstructor <?, ?> constructor ) {
162
210
163
211
try {
164
- return (ObjectInstantiator ) this .generator .generateCustomInstantiatorClass (entity ).newInstance ();
212
+ return (ObjectInstantiator ) this .generator .generateCustomInstantiatorClass (entity , constructor ).newInstance ();
165
213
} catch (Exception e ) {
166
214
throw new RuntimeException (e );
167
215
}
@@ -172,11 +220,10 @@ private ObjectInstantiator createObjectInstantiator(PersistentEntity<?, ?> entit
172
220
*
173
221
* @author Thomas Darimont
174
222
* @author Oliver Gierke
223
+ * @author Mark Paluch
175
224
*/
176
225
private static class EntityInstantiatorAdapter implements EntityInstantiator {
177
226
178
- private static final Object [] EMPTY_ARRAY = new Object [0 ];
179
-
180
227
private final ObjectInstantiator instantiator ;
181
228
182
229
/**
@@ -203,6 +250,8 @@ public <T, E extends PersistentEntity<? extends T, P>, P extends PersistentPrope
203
250
return (T ) instantiator .newInstance (params );
204
251
} catch (Exception e ) {
205
252
throw new MappingInstantiationException (entity , Arrays .asList (params ), e );
253
+ } finally {
254
+ deallocateArguments (params );
206
255
}
207
256
}
208
257
@@ -216,17 +265,18 @@ public <T, E extends PersistentEntity<? extends T, P>, P extends PersistentPrope
216
265
private <P extends PersistentProperty <P >, T > Object [] extractInvocationArguments (
217
266
@ Nullable PreferredConstructor <? extends T , P > constructor , ParameterValueProvider <P > provider ) {
218
267
219
- if (provider == null || constructor == null || !constructor .hasParameters ()) {
220
- return EMPTY_ARRAY ;
268
+ if (constructor == null || !constructor .hasParameters ()) {
269
+ return allocateArguments ( 0 ) ;
221
270
}
222
271
223
- List < Object > params = new ArrayList <> (constructor .getConstructor ().getParameterCount ());
272
+ Object [] params = allocateArguments (constructor .getConstructor ().getParameterCount ());
224
273
274
+ int index = 0 ;
225
275
for (Parameter <?, P > parameter : constructor .getParameters ()) {
226
- params . add ( provider .getParameterValue (parameter ) );
276
+ params [ index ++] = provider .getParameterValue (parameter );
227
277
}
228
278
229
- return params . toArray () ;
279
+ return params ;
230
280
}
231
281
}
232
282
@@ -290,7 +340,7 @@ static class ObjectInstantiatorClassGenerator {
290
340
291
341
private final ByteArrayClassLoader classLoader ;
292
342
293
- private ObjectInstantiatorClassGenerator () {
343
+ ObjectInstantiatorClassGenerator () {
294
344
295
345
this .classLoader = AccessController .doPrivileged (
296
346
(PrivilegedAction <ByteArrayClassLoader >) () -> new ByteArrayClassLoader (ClassUtils .getDefaultClassLoader ()));
@@ -300,12 +350,14 @@ private ObjectInstantiatorClassGenerator() {
300
350
* Generate a new class for the given {@link PersistentEntity}.
301
351
*
302
352
* @param entity
353
+ * @param constructor
303
354
* @return
304
355
*/
305
- public Class <?> generateCustomInstantiatorClass (PersistentEntity <?, ?> entity ) {
356
+ public Class <?> generateCustomInstantiatorClass (PersistentEntity <?, ?> entity ,
357
+ @ Nullable PreferredConstructor <?, ?> constructor ) {
306
358
307
359
String className = generateClassName (entity );
308
- byte [] bytecode = generateBytecode (className , entity );
360
+ byte [] bytecode = generateBytecode (className , entity , constructor );
309
361
310
362
return classLoader .loadClass (className , bytecode );
311
363
}
@@ -323,9 +375,11 @@ private String generateClassName(PersistentEntity<?, ?> entity) {
323
375
*
324
376
* @param internalClassName
325
377
* @param entity
378
+ * @param constructor
326
379
* @return
327
380
*/
328
- public byte [] generateBytecode (String internalClassName , PersistentEntity <?, ?> entity ) {
381
+ public byte [] generateBytecode (String internalClassName , PersistentEntity <?, ?> entity ,
382
+ @ Nullable PreferredConstructor <?, ?> constructor ) {
329
383
330
384
ClassWriter cw = new ClassWriter (ClassWriter .COMPUTE_MAXS );
331
385
@@ -334,7 +388,7 @@ public byte[] generateBytecode(String internalClassName, PersistentEntity<?, ?>
334
388
335
389
visitDefaultConstructor (cw );
336
390
337
- visitCreateMethod (cw , entity );
391
+ visitCreateMethod (cw , entity , constructor );
338
392
339
393
cw .visitEnd ();
340
394
@@ -357,8 +411,10 @@ private void visitDefaultConstructor(ClassWriter cw) {
357
411
*
358
412
* @param cw
359
413
* @param entity
414
+ * @param constructor
360
415
*/
361
- private void visitCreateMethod (ClassWriter cw , PersistentEntity <?, ?> entity ) {
416
+ private void visitCreateMethod (ClassWriter cw , PersistentEntity <?, ?> entity ,
417
+ @ Nullable PreferredConstructor <?, ?> constructor ) {
362
418
363
419
String entityTypeResourcePath = Type .getInternalName (entity .getType ());
364
420
@@ -368,8 +424,6 @@ private void visitCreateMethod(ClassWriter cw, PersistentEntity<?, ?> entity) {
368
424
mv .visitTypeInsn (NEW , entityTypeResourcePath );
369
425
mv .visitInsn (DUP );
370
426
371
- PreferredConstructor <?, ?> constructor = entity .getPersistenceConstructor ();
372
-
373
427
if (constructor != null ) {
374
428
375
429
Constructor <?> ctor = constructor .getConstructor ();
0 commit comments