Во время выполнения классы 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
|
@Configurationpublic 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.