
Добрый день!
Я вдохновился приглашением продолжить публикацию, поэтому продолжаю.
В этот раз мы рассмотрим основные варианты внедрения зависимости — через конструктор и через сеттеры. Все исходники искать здесь
Урок 06. Внедрение через конструктор.
Снова возьмем за основу проект из урока 2.
Добавим еще одного поэта. src\main\java\spring\impls\Severyanin.java
package spring.impls;
import spring.intarfaces.Lyricist;
public class Severyanin implements Lyricist {
@Override
public String Generate() {
return "Это было у моря, где ажурная пена,\r\n" + "Где встречается редко городской экипаж…\r\n"
+ "Королева играла — в башне замка — Шопена,\r\n" + "И, внимая Шопену, полюбил её паж. ";
}
}
Зарегистрируем класс в конфигурационном файле src\main\resources\ApplicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="LyricistBean1" class="spring.impls.Poushkin"/>
<bean id="LyricistBean2" class="spring.impls.Mayakovsky"/>
<bean id="LyricistBean3" class="spring.impls.Severyanin"/>
</beans>
В начале двадцатого века были очень популярны литературные дуэли.
Устроим литературную дуэль между двумя поэтами. Для этого создадим сцену src\main\java\spring\impls\ Stage.java
package spring.impls;
import spring.intarfaces.Lyricist;
public class Stage {
private Lyricist lyr1;
private Lyricist lyr2;
public Stage(Lyricist lyr1, Lyricist lyr2) {
this.lyr1 = lyr1;
this.lyr2 = lyr2;
}
public void Act() {
System.out.println("Первый поэт:");
System.out.println(lyr1.Generate());
System.out.println();
System.out.println("Второй поэт:");
System.out.println(lyr2.Generate());
System.out.println();
System.out.print("В литературной дуэли победил ");
if (Math.random() < 0.1) {
System.out.println("Первый поэт.");
} else {
System.out.println("Второй поэт.");
}
}
}
В принципе, можно изменить src\main\java\spring\main\ Start.java – и все заработает:
package spring.main;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import spring.impls.Stage;
import spring.intarfaces.Lyricist;
public class Start {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
Lyricist lyr1 = context.getBean("LyricistBean2", Lyricist.class);
Lyricist lyr2 = context.getBean("LyricistBean3", Lyricist.class);
Stage myStage = new Stage(lyr1, lyr2);
myStage.Act();
((ConfigurableApplicationContext) context).close();// закрытие контекста
}
}
Запускаем – все работает. Поэты выдали по одному шедевру, второй, скорее всего, победил. Так и должно быть, 27 февраля 1918 года в Политехническом музее на Избрании короля поэтов Северянин победил Маяковского. Но мы дали Владимиру Владимировичу небольшой шанс. Может быть, в вашей версии победил он.
Теперь вынесем все настройки в конфигурационный файл src\main\resources\ApplicationContext.xml, негоже явно в стартовом файле конфигурировать бины.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="LyricistBean1" class="spring.impls.Poushkin"/>
<bean id="LyricistBean2" class="spring.impls.Mayakovsky"/>
<bean id="LyricistBean3" class="spring.impls.Severyanin"/>
<bean id="StageBean" class="spring.impls.Stage">
<constructor-arg ref="LyricistBean2" />
<constructor-arg ref="LyricistBean3" />
</bean>
</beans>
Обычно бины создаются с конструктором по умолчанию без аргументов. Но в нашем случае он не подойдет. Передадим в качестве аргументов ссылки на другие создаваемые бины Маяковского и Северянина.
Осталось убрать все лишнее из класса src\main\java\spring\main\ Start.java
package spring.main;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import spring.impls.Stage;
public class Start {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
Stage myStage = context.getBean("StageBean", Stage.class);
myStage.Act();
((ConfigurableApplicationContext) context).close();// закрытие контекста
}
}
Запускаем. Все работает. Бины создаются. Северянин вновь победил.
Во всяком случае, в моей реальности.
Теперь посмотрим, каким образом можно сконфигурировать сеттеры.
Урок 07. Внедрение через сеттеры.
Продолжим терзать предыдущий проект.
Наверное, неправильно при создании сцены создавать и поэтов.
Исправим эту оплошность и немного изменим класс сцены. Удалим конструктор и добавим сеттеры для lyr1 и lyr2 из src\main\java\spring\impls\ Stage.java
package spring.impls;
import spring.intarfaces.Lyricist;
public class Stage {
private Lyricist lyr1;
private Lyricist lyr2;
public void setLyr1(Lyricist lyr1) {
this.lyr1 = lyr1;
}
public void setLyr2(Lyricist lyr2) {
this.lyr2 = lyr2;
}
public void Act() {
System.out.println("Первый поэт:");
System.out.println(lyr1.Generate());
System.out.println();
System.out.println("Второй поэт:");
System.out.println(lyr2.Generate());
System.out.println();
System.out.print("В литературной дуэли победил ");
if (Math.random() < 0.1) {
System.out.println("Первый поэт.");
} else {
System.out.println("Второй поэт.");
}
}
}
Изменим конфигурационный файл src\main\resources\ApplicationContext.xml. Уберем аргументы конструктора и добавим значения сеттеров.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="LyricistBean1" class="spring.impls.Poushkin"/>
<bean id="LyricistBean2" class="spring.impls.Mayakovsky"/>
<bean id="LyricistBean3" class="spring.impls.Severyanin"/>
<bean id="StageBean" class="spring.impls.Stage">
<property name="lyr1" ref="LyricistBean2"></property>
<property name="lyr2" ref="LyricistBean3"></property>
</bean>
</beans>
Класс старт в данном случае можно не трогать. Запускаем. Все работает. Отметим, что для сцены не запускается конструктор с двумя параметрами, зато после создания сцены устанавливаются два сеттера.
Продолжение следует…
Комментарии (15)
pavzay
24.08.2018 11:02LyricistBean1, LyricistBean2, ... Act, Generate, ...
По правилам именования, названия методов и экземпляров класса (id бинов) должны начинаться с маленькой буквы.
private Lyricist lyr1; private Lyricist lyr2; public Stage(Lyricist lyr1, Lyricist lyr2) { this.lyr1 = lyr1; this.lyr2 = lyr2; }
При внедрении через конструктор поля, в которые происходит внедрение, должны помечаться final.semyong
24.08.2018 13:37Еще внедрение через конструктор помогает выявлять циклические зависимости, а чтобы не мучаться с конструктором можно использовать Lombok:
@RequiredArgsConstructor(onConstructor_ = {@Autowired}) public class Service...
Sultansoy
24.08.2018 17:21А можно и вовсе без autowired, если у вас один конструктор. Но лично, когда речь идет про инжект конструктор, я всегда использую Alt+Insert в Intellij. Как минимум, можно потыкать и посмотреть, какой бин и где инжектится.
А иногда бывают сложные случаи, когда несколько бинов одного класса, а вам надо заинжектить их в 3 экземпляра другого класса, и там тоже такая красивая ломбоковская конструкция не спасает.
Ломбок идеален для POJO, чтобы не писать геттеры, сеттеры и прочее, а заменить Data. Также, если логирование простое без заморочек, можно побаловать себя ломбоком, но вот такие конструкции скорее вредят, нежели помогают.
Sultansoy
24.08.2018 17:24+1Было бы неплохо описать разницу в методах инжекта, рассказать о том, когда все использовать. И неплохо бы соблюдать нормальный code style. Очень непривычно видеть названия методов в upper camel case. Как-то по-шарповому это.
Bonart
Регистрация классов через XML в 2018 году смотрится очень тепло и лампово.
aleksandy
В одном из докладов Евгения Борисова было сравнение времени поднятия контекста. И оно было не в пользу java config.
AstarothAst
Это играло бы рояль, если контекст приходилось бы поднимать многократно, а разница в несколько даже секунд на старте приложения мало что значит, особенно если приложение призвано работать непрерывно в течение долгого времени.
aleksandy
Нашёл.
может быть критична, если время на запуск лимитировано.
Например, на heroku, если через 30 секунд приложение не отзывается, то приложение убивается.
AstarothAst
Если ваше приложение на спринге взлетает дольше 30 секунд, то, сдается мне, дело явно не в том javaconfig у вас используется или xml… В общем экономия на спичках.
levap
Сильно от ресурсов машины зависит, особенно от кол-ва доступных ядер процессора, т.к. старт спринга неплохо параллелится. У меня было такое, что одно и то же приложение запускалось на одной машине 14 сек, а на другой почти 70. При этом скорость работы после запуска субъективно была практически одинаковая на небольшой нагрузке.
AstarothAst
70 секунд??? У нас какие-то разные спринги, наверное. Голое приложение на простом спринге с jetty в качестве контейнера запускается буквально пару секунд и почти не жрет памяти. Голое приложение на спринг-буте запускается чуть дольше, но тоже в пределах, ну, пусть, 10 секунд, и жрет 15 метров памяти, или что-то около того. Не могу представить, что должно подниматься что бы это занимало 70 секунд…
smitevg
Есть 3 типа описания конфигурации:
Xml, Aннотации, java config.
Аннотации не уступаю в скорости поднятия контекста XML-ю
Bonart
Быстродействие как главный критерий выбора xml вместо кода — тут уже не лампами, а дымком от костра попахивает.
Sultansoy
Грустно видеть такое, когда с нуля пишут какое-то приложение в продакшн в 2018 году. А еще хуже, когда смешивают спринг бут, хмл конфиг, джава конфиг и аннотации. Такой франкенштейн тоже, увы, повстречался.