Как я изучаю фреймворк Spring — часть 2 (помощь начинающим — дело рук самих начинающих)

  • Tutorial


Добрый день!

Я вдохновился приглашением продолжить публикацию, поэтому продолжаю.

В этот раз мы рассмотрим основные варианты внедрения зависимости — через конструктор и через сеттеры. Все исходники искать здесь

Урок 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>

Класс старт в данном случае можно не трогать. Запускаем. Все работает. Отметим, что для сцены не запускается конструктор с двумя параметрами, зато после создания сцены устанавливаются два сеттера.

Продолжение следует…
Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 15

    +1
    Регистрация классов через XML в 2018 году смотрится очень тепло и лампово.
      0
      В одном из докладов Евгения Борисова было сравнение времени поднятия контекста. И оно было не в пользу java config.
        +3
        Это играло бы рояль, если контекст приходилось бы поднимать многократно, а разница в несколько даже секунд на старте приложения мало что значит, особенно если приложение призвано работать непрерывно в течение долгого времени.
          –1
          Нашёл.

          разница в несколько даже секунд на старте приложения

          может быть критична, если время на запуск лимитировано.

          Например, на heroku, если через 30 секунд приложение не отзывается, то приложение убивается.
            +1
            Если ваше приложение на спринге взлетает дольше 30 секунд, то, сдается мне, дело явно не в том javaconfig у вас используется или xml… В общем экономия на спичках.
              –1
              Сильно от ресурсов машины зависит, особенно от кол-ва доступных ядер процессора, т.к. старт спринга неплохо параллелится. У меня было такое, что одно и то же приложение запускалось на одной машине 14 сек, а на другой почти 70. При этом скорость работы после запуска субъективно была практически одинаковая на небольшой нагрузке.
                0
                70 секунд??? У нас какие-то разные спринги, наверное. Голое приложение на простом спринге с jetty в качестве контейнера запускается буквально пару секунд и почти не жрет памяти. Голое приложение на спринг-буте запускается чуть дольше, но тоже в пределах, ну, пусть, 10 секунд, и жрет 15 метров памяти, или что-то около того. Не могу представить, что должно подниматься что бы это занимало 70 секунд…
          0
          Есть 3 типа описания конфигурации:
          Xml, Aннотации, java config.
          Аннотации не уступаю в скорости поднятия контекста XML-ю
            0
            Быстродействие как главный критерий выбора xml вместо кода — тут уже не лампами, а дымком от костра попахивает.
            0
            Грустно видеть такое, когда с нуля пишут какое-то приложение в продакшн в 2018 году. А еще хуже, когда смешивают спринг бут, хмл конфиг, джава конфиг и аннотации. Такой франкенштейн тоже, увы, повстречался.
            0
            LyricistBean1, LyricistBean2, ...
            Act, Generate, ...
            

            По правилам именования, названия методов и экземпляров класса (id бинов) должны начинаться с маленькой буквы.

            	private Lyricist lyr1;
            	private Lyricist lyr2;
            
            	public Stage(Lyricist lyr1, Lyricist lyr2) {
            		this.lyr1 = lyr1;
            		this.lyr2 = lyr2;
            	}

            При внедрении через конструктор поля, в которые происходит внедрение, должны помечаться final.
              0
              Еще внедрение через конструктор помогает выявлять циклические зависимости, а чтобы не мучаться с конструктором можно использовать Lombok:
              @RequiredArgsConstructor(onConstructor_ = {@Autowired})
              public class Service...
              
                0
                Тот случай, когда «мучение» с конструктором короче, да и нагляднее :)
                  0
                  А можно и вовсе без autowired, если у вас один конструктор. Но лично, когда речь идет про инжект конструктор, я всегда использую Alt+Insert в Intellij. Как минимум, можно потыкать и посмотреть, какой бин и где инжектится.
                  А иногда бывают сложные случаи, когда несколько бинов одного класса, а вам надо заинжектить их в 3 экземпляра другого класса, и там тоже такая красивая ломбоковская конструкция не спасает.
                  Ломбок идеален для POJO, чтобы не писать геттеры, сеттеры и прочее, а заменить Data. Также, если логирование простое без заморочек, можно побаловать себя ломбоком, но вот такие конструкции скорее вредят, нежели помогают.
                +1
                Было бы неплохо описать разницу в методах инжекта, рассказать о том, когда все использовать. И неплохо бы соблюдать нормальный code style. Очень непривычно видеть названия методов в upper camel case. Как-то по-шарповому это.

                Only users with full accounts can post comments. Log in, please.