Во время выполнения классы java не сохраняют имя параметров конструктора или метода, если только классы не скомпилированы с опциями отладки.
Это имеет некоторые интересные последствия для Spring Constructor Injection .
Рассмотрим следующий простой класс
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package dbg; public class Person { private final String first; private final String last; private final Address address; public Person(String first, String last, Address address){ this .first = first; this .last = last; this .address = address; } public String getFirst() { return first; } public String getLast() { return last; } public Address getAddress() { return address; } } |
и пример XML-файла конфигурации Spring bean:
1
2
3
|
< bean name = 'address1' class = 'dbg.Address' p:street1 = 'street1' p:street2 = 'street1' p:state = 'state1' /> < bean name = 'person1' class = 'dbg.Person' c:address-ref = 'address1' c:last = 'Last1' c:first = 'First1' ></ bean > < bean name = 'person2' class = 'dbg.Person' c:first = 'First2' c:address-ref = 'address1' c:last = 'Last2' ></ bean > |
Здесь я использую пространство имен c для конструктора. Это терпит неудачу за исключением того, что типы аргументов являются неоднозначными — это потому, что первый аргумент является строкой, и поскольку его представление во время выполнения не имеет имени аргумента, Spring не может определить, следует ли заменить его именем или фамилией. В этом сценарии возможны несколько исправлений: 1. Использование внедрения на основе индекса, однако недостатком является то, что он очень многословен:
01
02
03
04
05
06
07
08
09
10
|
< bean name = 'person1' class = 'dbg.Person' > < constructor-arg value = 'First1' ></ constructor-arg > < constructor-arg value = 'Last1' ></ constructor-arg > < constructor-arg ref = 'address1' ></ constructor-arg > </ bean > < bean name = 'person2' class = 'dbg.Person' > < constructor-arg value = 'First2' ></ constructor-arg > < constructor-arg value = 'Last2' ></ constructor-arg > < constructor-arg ref = 'address1' ></ constructor-arg > </ bean > |
2. Чтобы компилировать с включенными символами отладки, это можно сделать, передав флаг -g или -g: var компилятору java — это обеспечит сохранение имен параметров в файле класса и исходной краткой конфигурации компонента с помощью c Пространство имен будет работать. 3. Аккуратное исправление — аннотировать конструктор с помощью @ConstructorProperties, который в основном предоставляет имена аргументов для Spring:
01
02
03
04
05
06
07
08
09
10
11
12
|
public class Person { private final String first; private final String last; private final Address address; @ConstructorProperties ({ 'first' , 'last' , 'address' }) public Person(String first, String last, Address address){ this .first = first; this .last = last; this .address = address; } |
Это работает с или без включенных параметров отладки. 4. Вероятно, лучшим решением будет просто использовать @Configuration для определения bean-компонентов:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
@Configuration public static class TestConfiguration{ @Bean public Address address1(){ return new Address(); } @Bean public Person person1(){ return new Person( 'First1' , 'Last1' , address1()); } @Bean public Person person2(){ return new Person( 'First2' , 'Last2' , address1()); } } |
Ссылка: имена Spring Constructor Injection и Argument от нашего партнера JCG Биджу Кунджуммена из блога all and sundry.