DI з урахуванням конструктора виконується шляхом виклику контейнером конструктора з низкою аргументів, кожен із яких
представляє залежність. Виклик статичного
фабричного методу з певними аргументами для створення біна
майже еквівалентний, і в цьому аналізі аргументи конструктора і статичного
фабричного методу
розглядаються однаково. У наступному прикладі показаний клас, залежність до якого може бути впроваджена виключно
через конструктор:
public class SimpleMovieLister {
// SimpleMovieLister має залежність від MovieFinder
private final MovieFinder movieFinder;
// конструктор для того, щоб контейнер Spring міг впровадити MovieFinder
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// Бізнес-логіка, яка фактично використовує впроваджений MovieFinder, опущена...
}
// конструктор для того, щоб контейнер Spring міг впровадити MovieFinder
class SimpleMovieLister(private val movieFinder: MovieFinder) {
// Бізнес-логіка, яка фактично використовує впроваджений MovieFinder, опущена...
}
Зверни увагу, що в цьому класі немає нічого особливого. Це POJO (простий об'єкт мови Java), який не залежить від конкретних інтерфейсів контейнера, базових класів або анотацій.
Дозволення аргументів конструктора
Зіставлення дозволення аргументу конструктора відбувається з використанням типу аргументу. Якщо в аргументах конструктора визначення біна немає потенційної неоднозначності, то порядок, у якому аргументи конструктора встановлені у визначенні біна, є порядком, у якому ці аргументи передаються відповідному конструктору під час створення біна. Розглянемо наступний клас:
package x.y;
public class ThingOne {
public ThingOne(ThingTwo thingTwo, ThingThree thingThree) {
// ...
}
}
package x.y
class ThingOne(thingTwo: ThingTwo, thingThree: ThingThree)
Якщо припустити, що класи ThingTwo
та ThingThree
не пов'язані успадкуванням, то потенційної
двозначності не виникає. Таким чином, наступна конфігурація працює нормально, і не потрібно чітко вказувати індекси
або типи аргументів конструктора в елементі <constructor-arg/>
.
<beans>
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg ref="beanTwo"/>
<constructor-arg ref="beanThree"/>
</bean>
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
</beans>
Якщо посилання надається на інший бін, то тип відомий, тому може відбутися зіставлення (як це було в попередньому
прикладі). Якщо використовується простий тип, наприклад <value>true</value>
, Spring не може
визначити тип значення, і тому не може виконати зіставлення за типом без сторонньої допомоги. Розглянемо наступний
клас:
package examples;
public class ExampleBean {
// Кількість років до розрахунку остаточної відповіді
private final int years;
// Відповідь на головне питання життя, всесвіту і всього такого
private final String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
package examples
class ExampleBean(
private val years: Int, // Кількість років для розрахунку остаточної відповіді
private val ultimateAnswer: String // Відповідь на головне питання життя, всесвіту і всього такого
)
У попередньому сценарії контейнер може задіяти зіставлення типів із простими типами, якщо тип аргументу конструктора
явно вказаний за допомогою атрибуту type
, як показано в наступному прикладі:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
Ти можеш використовувати атрибут index
, щоб явно вказати індекс аргументів конструктора, як показано в
наступному прикладі:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
Окрім усунення неоднозначності кількох простих значень, зазначення індексу усуває неоднозначність, якщо конструктор має два аргументи одного типу.
Також можна використовувати ім'я параметра конструктора для усунення суперечностей значень, як показано в наступному прикладі:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</bean>
Май на увазі: щоб це працювало "з коробки", код повинен бути скомпільований з увімкненим прапорцем налагодження (debug), щоб Spring міг знайти ім'я параметра в конструкторі. Якщо ти не можеш або не хочеш компілювати свій код з прапорцем налагодження, можна використовувати анотацію @ConstructorProperties JDK для явного іменування аргументів твого конструктора. Тоді зразок класу має виглядати так:
package examples;
public class ExampleBean {
// Поля опущені
@ConstructorProperties({"years", "ultimateAnswer"})
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
package examples
class ExampleBean
@ConstructorProperties("years", "ultimateAnswer")
constructor(val years: Int, val ultimateAnswer: String)
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ