I understand Spring DI and how it works in general.
But what I cannot understand here is in case of @Bean
method parameter injection, how spring knows about the parameter name so it could inject beans from its bean's factory based on the parameter's name?
For example, In the following example, the methods fernas1
and fernas2
parameters are being wiped at runtime. however, spring still can inject the correct Abbas
bean instance into it.
@SpringBootApplication
public class DemoApplication {
@Autowired
private Abbas abbas1; // this is understandable, hence the field name is available at runtime
@Autowired
private Abbas abbas2; // this is understandable, hence the field name is available at runtime
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(DemoApplication.class, args);
Map<String, Fernas> beansOfType = ctx.getBeansOfType(Fernas.class);
System.out.println(beansOfType);
Arrays.stream(DemoApplication.class.getMethods())
.filter(m -> m.getName().startsWith("fernas"))
.flatMap(m -> Stream.of(m.getParameters()))
.map(Parameter::getName)
.forEach(System.out::println);
System.out.println(ctx.getBean(DemoApplication.class).abbas1);
System.out.println(ctx.getBean(DemoApplication.class).abbas2);
}
class Abbas {
String name;
@Override
public String toString() {
return name;
}
}
class Fernas {
Abbas abbas;
@Override
public String toString() {
return abbas.toString();
}
}
@Bean
public Abbas abbas1() {
Abbas abbas = new Abbas();
abbas.name = "abbas1";
return abbas;
}
@Bean
public Abbas abbas2() {
Abbas abbas = new Abbas();
abbas.name = "abbas2";
return abbas;
}
// this is not understandable, hence the parameter name is NOT available at runtime
@Bean
public Fernas fernas1(Abbas abbas1) {
Fernas fernas1 = new Fernas();
fernas1.abbas = abbas1;
return fernas1;
}
// this is not understandable, hence the parameter name is NOT available at runtime
@Bean
public Fernas fernas2(Abbas abbas2) {
Fernas fernas2 = new Fernas();
fernas2.abbas = abbas2;
return fernas2;
}
}
EDIT: The same problem and solution by @Javier both works on method
and constructor
parameters.
If parameter name reflection is not available, it uses the information in the class file itself. See DefaultParameterNameDiscoverer
Default implementation of the ParameterNameDiscoverer strategy interface, using the Java 8 standard reflection mechanism (if available), and falling back to the ASM-based LocalVariableTableParameterNameDiscoverer for checking debug information in the class file.
For instance, the LocalVariableTable of DemoApplication.fernas2
is
Start Length Slot Name Signature
0 16 0 this Lcom/example/demo/DemoApplication;
0 16 1 abbas2 Lcom/example/demo/DemoApplication$Abbas;
9 7 2 fernas2 Lcom/example/demo/DemoApplication$Fernas;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With