17
17
package org .springframework .beans .factory .annotation ;
18
18
19
19
import java .beans .PropertyDescriptor ;
20
+ import java .io .IOException ;
20
21
import java .lang .annotation .Annotation ;
21
22
import java .lang .reflect .AccessibleObject ;
22
23
import java .lang .reflect .Constructor ;
62
63
import org .springframework .core .annotation .AnnotationUtils ;
63
64
import org .springframework .core .annotation .MergedAnnotation ;
64
65
import org .springframework .core .annotation .MergedAnnotations ;
66
+ import org .springframework .core .type .AnnotationMetadata ;
67
+ import org .springframework .core .type .MethodMetadata ;
68
+ import org .springframework .core .type .classreading .MetadataReaderFactory ;
69
+ import org .springframework .core .type .classreading .SimpleMetadataReaderFactory ;
65
70
import org .springframework .lang .Nullable ;
66
71
import org .springframework .util .Assert ;
67
72
import org .springframework .util .ClassUtils ;
@@ -144,6 +149,9 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
144
149
@ Nullable
145
150
private ConfigurableListableBeanFactory beanFactory ;
146
151
152
+ @ Nullable
153
+ private MetadataReaderFactory metadataReaderFactory ;
154
+
147
155
private final Set <String > lookupMethodsChecked = Collections .newSetFromMap (new ConcurrentHashMap <>(256 ));
148
156
149
157
private final Map <Class <?>, Constructor <?>[]> candidateConstructorsCache = new ConcurrentHashMap <>(256 );
@@ -238,6 +246,7 @@ public void setBeanFactory(BeanFactory beanFactory) {
238
246
"AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory: " + beanFactory );
239
247
}
240
248
this .beanFactory = (ConfigurableListableBeanFactory ) beanFactory ;
249
+ this .metadataReaderFactory = new SimpleMetadataReaderFactory (this .beanFactory .getBeanClassLoader ());
241
250
}
242
251
243
252
@@ -463,12 +472,11 @@ private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
463
472
return InjectionMetadata .EMPTY ;
464
473
}
465
474
466
- List <InjectionMetadata .InjectedElement > elements = new ArrayList <>();
475
+ final List <InjectionMetadata .InjectedElement > elements = new ArrayList <>();
467
476
Class <?> targetClass = clazz ;
468
477
469
478
do {
470
- final List <InjectionMetadata .InjectedElement > currElements = new ArrayList <>();
471
-
479
+ final List <InjectionMetadata .InjectedElement > fieldElements = new ArrayList <>();
472
480
ReflectionUtils .doWithLocalFields (targetClass , field -> {
473
481
MergedAnnotation <?> ann = findAutowiredAnnotation (field );
474
482
if (ann != null ) {
@@ -479,10 +487,11 @@ private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
479
487
return ;
480
488
}
481
489
boolean required = determineRequiredStatus (ann );
482
- currElements .add (new AutowiredFieldElement (field , required ));
490
+ fieldElements .add (new AutowiredFieldElement (field , required ));
483
491
}
484
492
});
485
493
494
+ final List <InjectionMetadata .InjectedElement > methodElements = new ArrayList <>();
486
495
ReflectionUtils .doWithLocalMethods (targetClass , method -> {
487
496
Method bridgedMethod = BridgeMethodResolver .findBridgedMethod (method );
488
497
if (!BridgeMethodResolver .isVisibilityBridgeMethodPair (method , bridgedMethod )) {
@@ -504,11 +513,12 @@ private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
504
513
}
505
514
boolean required = determineRequiredStatus (ann );
506
515
PropertyDescriptor pd = BeanUtils .findPropertyForMethod (bridgedMethod , clazz );
507
- currElements .add (new AutowiredMethodElement (method , required , pd ));
516
+ methodElements .add (new AutowiredMethodElement (method , required , pd ));
508
517
}
509
518
});
510
519
511
- elements .addAll (0 , currElements );
520
+ elements .addAll (0 , sortMethodElements (methodElements , targetClass ));
521
+ elements .addAll (0 , fieldElements );
512
522
targetClass = targetClass .getSuperclass ();
513
523
}
514
524
while (targetClass != null && targetClass != Object .class );
@@ -573,6 +583,47 @@ protected <T> Map<String, T> findAutowireCandidates(Class<T> type) throws BeansE
573
583
return BeanFactoryUtils .beansOfTypeIncludingAncestors (this .beanFactory , type );
574
584
}
575
585
586
+ /**
587
+ * Sort the method elements via ASM for deterministic declaration order if possible.
588
+ */
589
+ private List <InjectionMetadata .InjectedElement > sortMethodElements (
590
+ List <InjectionMetadata .InjectedElement > methodElements , Class <?> targetClass ) {
591
+
592
+ if (this .metadataReaderFactory != null && methodElements .size () > 1 ) {
593
+ // Try reading the class file via ASM for deterministic declaration order...
594
+ // Unfortunately, the JVM's standard reflection returns methods in arbitrary
595
+ // order, even between different runs of the same application on the same JVM.
596
+ try {
597
+ AnnotationMetadata asm =
598
+ this .metadataReaderFactory .getMetadataReader (targetClass .getName ()).getAnnotationMetadata ();
599
+ Set <MethodMetadata > asmMethods = asm .getAnnotatedMethods (Autowired .class .getName ());
600
+ if (asmMethods .size () >= methodElements .size ()) {
601
+ List <InjectionMetadata .InjectedElement > candidateMethods = new ArrayList <>(methodElements );
602
+ List <InjectionMetadata .InjectedElement > selectedMethods = new ArrayList <>(asmMethods .size ());
603
+ for (MethodMetadata asmMethod : asmMethods ) {
604
+ for (Iterator <InjectionMetadata .InjectedElement > it = candidateMethods .iterator (); it .hasNext ();) {
605
+ InjectionMetadata .InjectedElement element = it .next ();
606
+ if (element .getMember ().getName ().equals (asmMethod .getMethodName ())) {
607
+ selectedMethods .add (element );
608
+ it .remove ();
609
+ break ;
610
+ }
611
+ }
612
+ }
613
+ if (selectedMethods .size () == methodElements .size ()) {
614
+ // All reflection-detected methods found in ASM method set -> proceed
615
+ return selectedMethods ;
616
+ }
617
+ }
618
+ }
619
+ catch (IOException ex ) {
620
+ logger .debug ("Failed to read class file via ASM for determining @Autowired method order" , ex );
621
+ // No worries, let's continue with the reflection metadata we started with...
622
+ }
623
+ }
624
+ return methodElements ;
625
+ }
626
+
576
627
/**
577
628
* Register the specified bean as dependent on the autowired beans.
578
629
*/
0 commit comments