|
20 | 20 | import java.lang.reflect.Method;
|
21 | 21 | import java.lang.reflect.Modifier;
|
22 | 22 | import java.lang.reflect.UndeclaredThrowableException;
|
| 23 | +import java.util.ArrayList; |
23 | 24 | import java.util.Collections;
|
24 | 25 | import java.util.List;
|
25 | 26 | import java.util.Map;
|
@@ -330,43 +331,57 @@ private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
|
330 | 331 | aopInterceptor, // for normal advice
|
331 | 332 | targetInterceptor, // invoke target without considering advice, if optimized
|
332 | 333 | new SerializableNoOp(), // no override for methods mapped to this
|
333 |
| - targetDispatcher, this.advisedDispatcher, |
| 334 | + targetDispatcher, |
| 335 | + this.advisedDispatcher, |
334 | 336 | new EqualsInterceptor(this.advised),
|
335 | 337 | new HashCodeInterceptor(this.advised)
|
336 | 338 | };
|
337 | 339 |
|
338 |
| - Callback[] callbacks; |
339 |
| - |
340 | 340 | // If the target is a static one and the advice chain is frozen,
|
341 | 341 | // then we can make some optimizations by sending the AOP calls
|
342 | 342 | // direct to the target using the fixed chain for that method.
|
343 | 343 | if (isStatic && isFrozen) {
|
344 | 344 | Method[] methods = rootClass.getMethods();
|
345 |
| - Callback[] fixedCallbacks = new Callback[methods.length]; |
346 |
| - this.fixedInterceptorMap = CollectionUtils.newHashMap(methods.length); |
| 345 | + int methodsCount = methods.length; |
| 346 | + ArrayList<Callback> fixedCallbacks = new ArrayList<>(methodsCount); |
| 347 | + this.fixedInterceptorMap = CollectionUtils.newHashMap(methodsCount); |
347 | 348 |
|
348 |
| - // TODO: small memory optimization here (can skip creation for methods with no advice) |
349 |
| - for (int x = 0; x < methods.length; x++) { |
| 349 | + int advicedMethodCount = methodsCount; |
| 350 | + for (int x = 0; x < methodsCount; x++) { |
350 | 351 | Method method = methods[x];
|
| 352 | + //do not create advices for non-overridden methods of java.lang.Object |
| 353 | + if (notOverriddenOfObject(method)) { |
| 354 | + advicedMethodCount--; |
| 355 | + continue; |
| 356 | + } |
351 | 357 | List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
|
352 |
| - fixedCallbacks[x] = new FixedChainStaticTargetInterceptor( |
353 |
| - chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass()); |
354 |
| - this.fixedInterceptorMap.put(method, x); |
| 358 | + fixedCallbacks.add(new FixedChainStaticTargetInterceptor( |
| 359 | + chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass())); |
| 360 | + this.fixedInterceptorMap.put(method, x - (methodsCount - advicedMethodCount) ); |
355 | 361 | }
|
356 | 362 |
|
357 | 363 | // Now copy both the callbacks from mainCallbacks
|
358 | 364 | // and fixedCallbacks into the callbacks array.
|
359 |
| - callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length]; |
| 365 | + Callback[] callbacks = new Callback[mainCallbacks.length + advicedMethodCount]; |
360 | 366 | System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
|
361 |
| - System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length); |
| 367 | + System.arraycopy(fixedCallbacks.toArray(), 0, callbacks, mainCallbacks.length, advicedMethodCount); |
362 | 368 | this.fixedInterceptorOffset = mainCallbacks.length;
|
| 369 | + return callbacks; |
363 | 370 | }
|
364 |
| - else { |
365 |
| - callbacks = mainCallbacks; |
366 |
| - } |
367 |
| - return callbacks; |
| 371 | + |
| 372 | + return mainCallbacks; |
368 | 373 | }
|
369 | 374 |
|
| 375 | + /** |
| 376 | + * Returns true if param is inherited from {@link Object} and not overridden in declaring class. |
| 377 | + * We use this to detect {@link Object#notify()}, {@link Object#notifyAll()}, {@link Object#getClass()} etc. |
| 378 | + * to skip creation of useless advices for them. |
| 379 | + * @param method to be checked |
| 380 | + * @return true in case {@code method} belongs to {@link Object} |
| 381 | + */ |
| 382 | + private static boolean notOverriddenOfObject(Method method) { |
| 383 | + return method.getDeclaringClass() == Object.class; |
| 384 | + } |
370 | 385 |
|
371 | 386 | @Override
|
372 | 387 | public boolean equals(@Nullable Object other) {
|
|
0 commit comments