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 ;
79
80
import org .springframework .core .annotation .AnnotationUtils ;
80
81
import org .springframework .core .annotation .MergedAnnotation ;
81
82
import org .springframework .core .annotation .MergedAnnotations ;
83
+ import org .springframework .core .type .AnnotationMetadata ;
84
+ import org .springframework .core .type .MethodMetadata ;
85
+ import org .springframework .core .type .classreading .MetadataReaderFactory ;
86
+ import org .springframework .core .type .classreading .SimpleMetadataReaderFactory ;
82
87
import org .springframework .javapoet .ClassName ;
83
88
import org .springframework .javapoet .CodeBlock ;
84
89
import org .springframework .lang .Nullable ;
@@ -167,6 +172,9 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
167
172
@ Nullable
168
173
private ConfigurableListableBeanFactory beanFactory ;
169
174
175
+ @ Nullable
176
+ private MetadataReaderFactory metadataReaderFactory ;
177
+
170
178
private final Set <String > lookupMethodsChecked = Collections .newSetFromMap (new ConcurrentHashMap <>(256 ));
171
179
172
180
private final Map <Class <?>, Constructor <?>[]> candidateConstructorsCache = new ConcurrentHashMap <>(256 );
@@ -271,6 +279,7 @@ public void setBeanFactory(BeanFactory beanFactory) {
271
279
"AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory: " + beanFactory );
272
280
}
273
281
this .beanFactory = clbf ;
282
+ this .metadataReaderFactory = new SimpleMetadataReaderFactory (clbf .getBeanClassLoader ());
274
283
}
275
284
276
285
@@ -539,12 +548,11 @@ private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
539
548
return InjectionMetadata .EMPTY ;
540
549
}
541
550
542
- List <InjectionMetadata .InjectedElement > elements = new ArrayList <>();
551
+ final List <InjectionMetadata .InjectedElement > elements = new ArrayList <>();
543
552
Class <?> targetClass = clazz ;
544
553
545
554
do {
546
- final List <InjectionMetadata .InjectedElement > currElements = new ArrayList <>();
547
-
555
+ final List <InjectionMetadata .InjectedElement > fieldElements = new ArrayList <>();
548
556
ReflectionUtils .doWithLocalFields (targetClass , field -> {
549
557
MergedAnnotation <?> ann = findAutowiredAnnotation (field );
550
558
if (ann != null ) {
@@ -555,10 +563,11 @@ private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
555
563
return ;
556
564
}
557
565
boolean required = determineRequiredStatus (ann );
558
- currElements .add (new AutowiredFieldElement (field , required ));
566
+ fieldElements .add (new AutowiredFieldElement (field , required ));
559
567
}
560
568
});
561
569
570
+ final List <InjectionMetadata .InjectedElement > methodElements = new ArrayList <>();
562
571
ReflectionUtils .doWithLocalMethods (targetClass , method -> {
563
572
Method bridgedMethod = BridgeMethodResolver .findBridgedMethod (method );
564
573
if (!BridgeMethodResolver .isVisibilityBridgeMethodPair (method , bridgedMethod )) {
@@ -580,11 +589,12 @@ private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
580
589
}
581
590
boolean required = determineRequiredStatus (ann );
582
591
PropertyDescriptor pd = BeanUtils .findPropertyForMethod (bridgedMethod , clazz );
583
- currElements .add (new AutowiredMethodElement (method , required , pd ));
592
+ methodElements .add (new AutowiredMethodElement (method , required , pd ));
584
593
}
585
594
});
586
595
587
- elements .addAll (0 , currElements );
596
+ elements .addAll (0 , sortMethodElements (methodElements , targetClass ));
597
+ elements .addAll (0 , fieldElements );
588
598
targetClass = targetClass .getSuperclass ();
589
599
}
590
600
while (targetClass != null && targetClass != Object .class );
@@ -617,6 +627,47 @@ protected boolean determineRequiredStatus(MergedAnnotation<?> ann) {
617
627
this .requiredParameterValue == ann .getBoolean (this .requiredParameterName ));
618
628
}
619
629
630
+ /**
631
+ * Sort the method elements via ASM for deterministic declaration order if possible.
632
+ */
633
+ private List <InjectionMetadata .InjectedElement > sortMethodElements (
634
+ List <InjectionMetadata .InjectedElement > methodElements , Class <?> targetClass ) {
635
+
636
+ if (this .metadataReaderFactory != null && methodElements .size () > 1 ) {
637
+ // Try reading the class file via ASM for deterministic declaration order...
638
+ // Unfortunately, the JVM's standard reflection returns methods in arbitrary
639
+ // order, even between different runs of the same application on the same JVM.
640
+ try {
641
+ AnnotationMetadata asm =
642
+ this .metadataReaderFactory .getMetadataReader (targetClass .getName ()).getAnnotationMetadata ();
643
+ Set <MethodMetadata > asmMethods = asm .getAnnotatedMethods (Autowired .class .getName ());
644
+ if (asmMethods .size () >= methodElements .size ()) {
645
+ List <InjectionMetadata .InjectedElement > candidateMethods = new ArrayList <>(methodElements );
646
+ List <InjectionMetadata .InjectedElement > selectedMethods = new ArrayList <>(asmMethods .size ());
647
+ for (MethodMetadata asmMethod : asmMethods ) {
648
+ for (Iterator <InjectionMetadata .InjectedElement > it = candidateMethods .iterator (); it .hasNext ();) {
649
+ InjectionMetadata .InjectedElement element = it .next ();
650
+ if (element .getMember ().getName ().equals (asmMethod .getMethodName ())) {
651
+ selectedMethods .add (element );
652
+ it .remove ();
653
+ break ;
654
+ }
655
+ }
656
+ }
657
+ if (selectedMethods .size () == methodElements .size ()) {
658
+ // All reflection-detected methods found in ASM method set -> proceed
659
+ return selectedMethods ;
660
+ }
661
+ }
662
+ }
663
+ catch (IOException ex ) {
664
+ logger .debug ("Failed to read class file via ASM for determining @Autowired method order" , ex );
665
+ // No worries, let's continue with the reflection metadata we started with...
666
+ }
667
+ }
668
+ return methodElements ;
669
+ }
670
+
620
671
/**
621
672
* Register the specified bean as dependent on the autowired beans.
622
673
*/
0 commit comments