Добрый день!
Я поставил себе цель изучить фреймфорк Spring для языка Java. Во время изучения решил проверить на себе алгоритм обучения Ричарда Фейнмана: организовать-упростить-обучить другого. В общем, я стал записывать серию коротких уроков для начинающих по работе в Spring. Для желающих повторить выложил исходный код.
Урок 01. Разбираемся с IoC
Итак, соберем вместе поэтов, пускай сочиняют и читают нам свои стихи.
Для начала объявим интерфейс, генерирующий стихи srcmainjavaspringinterfacesLyricist.java:
package spring.intarfaces;
public interface Lyricist {
public String Generate();
}
Реализуем этот интерфейс в классе srcmainjavaspringimplsMayakovsky.java:
package spring.impls;
import spring.intarfaces.Lyricist;
public class Mayakovsky implements Lyricist {
@Override
public String Generate() {
return "А выrn" + "ноктюрн сыгратьrn" + "могли быrn" + "на флейте водосточных труб?";
}
}
Пропишем, что будем создавать конкретный объект Mayakovsky в конфигурационном xml-файле srcmainresourcesApplicationContext.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.Mayakovsky"/>
</beans>
Связали id LyricistBean1 c именем класса Mayakovsky. Почти все готово, не хватает только вызывающего класса srcmainjavaspringmainStart.java:
package spring.main;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import spring.intarfaces.Lyricist;
public class Start {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
Lyricist lyr1 = context.getBean("LyricistBean1", Lyricist.class);
System.out.println(lyr1.Generate());
((ConfigurableApplicationContext) context).close();// закрытие контекста вручную
}
}
В классе Start мы прочитали наш конфигурационный файл, создали экземпляр поэта по имени бина LyricistBean1. Получили экземпляр поэта Mayakovsky. Функция Generate() вернула нам бессмертные строки:
А вы
ноктюрн сыграть
могли бы
на флейте водосточных труб?
Урок 02. Выбор создаваемого экземпляра через конфигурационный файл
Допустим, друг помог нам и предоставил другую реализацию нашего интерфейса Lyricist srcmainjavaspringimplsPoushkin.java:
package spring.impls;
import spring.intarfaces.Lyricist;
public class Poushkin implements Lyricist {
@Override
public String Generate() {
return "Я помню чудное мгновенье:rn" + "Передо мной явилась ты,rn" + "Как мимолетное виденье,rn"
+ "Как гений чистой красоты.";
}
}
Изменим в конфигурационном файле ApplicationContext.xml слово Mayakovsky на слово Poushkin.
Запускаем программу. Получаем без пересборки совсем другой результат:
Я помню чудное мгновенье
Передо мной явилась ты,
Как мимолетное виденье,
Как гений чистой красоты.
Урок 03. Бины в коде, а не в конфигурационном файле
Допустим, нам не нравится отдавать выбор создаваемого класса поэта в руки судьбы в конфигурационный файл.
Изменим класс Poushkin.java
- Добавим импорт библиотеки import org.springframework.stereotype.Component;
- Поставим аннотацию Component(«LyricistBean1») перед объявлением класса
Таким образом мы намекнули Spring, что хотим в виде первого поэта видеть именно Poushkin, а никак не кого-то другого.
Осталось чуть-чуть исправить конфигурационный файл ApplicationContext.xml:
1. Добавим сверху пространство имен context: xmlns:context=«www.springframework.org/schema/context»;
2. Удалим ненужную строку: />
3. Добавим вместо нее команду автоматически добавлять в программу бины из всех классов, расположенных в каталоге spring.impls:
<context:component-scan base-package=«spring.impls»/>
В итоге файл 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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan base-package="spring.impls"/>
</beans>
Запускаем. Получаем тот же результат, что и в предыдущем уроке.
Урок 04. Конфигурационный класс
Избавимся совсем от xml-файла.
Все настройки могут находиться и в java-классе. Иногда это удобно.
Добавим специальный настроечный класс srcmainjavaspringmainLyricistConfiguration.java в нашу программу:
package spring.main;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ComponentScan(basePackages = { "spring.impls" })
@Configuration
public class LyricistConfiguration {
}
@ComponentScan показывает, в каком каталоге искать бины.
@Configuration сообщает, что наш класс специальный, конфигурационный.
Все, xml-файл больше не нужен. Осталось сообщить эту новость нашему основному классу:
- Дополним его нужным импортом import org.springframework.context.annotation.AnnotationConfigApplicationContext;
- Заменим строку создания контекста
ApplicationContext context = new AnnotationConfigApplicationContext(LyricistConfiguration.class);
В итоге главный файл srcmainjavaspringmainStart.java должен выглядеть вот так:
package spring.main;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import spring.intarfaces.Lyricist;
public class Start {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(LyricistConfiguration.class);
Lyricist lyr1 = context.getBean("LyricistBean1", Lyricist.class);
System.out.println(lyr1.Generate());
((ConfigurableApplicationContext) context).close();// закрытие контекста вручную
}
}
Все запускается и по-прежнему выдает бессмертные Пушкинские строки. Все работает. Но уже без xml.
Урок 05. Singleton и Prototype
Исследуем возможности конфигурационного файла. Поэтому вернемся пока к проекту из второго урока. Попробуем в Start.java создать два экземпляра класса Poushkin и удостоверимся, что великий поэт один и тот же:
Lyricist lyr1 = context.getBean("LyricistBean1", Lyricist.class);
System.out.println(lyr1.Generate());
System.out.println(lyr1.hashCode());
Lyricist lyr2 = context.getBean("LyricistBean1", Lyricist.class);
System.out.println(lyr2.Generate());
System.out.println(lyr2.hashCode());
И стихи одни и те же, и хэш-код сорпадает. Все в порядке.
Добавим в наш проект простого гражданина, не пишущего стихи srcmainjavaspringimplsSimpleMan.java:
package spring.impls;
import spring.intarfaces.Lyricist;
public class SimpleMan implements Lyricist {
@Override
public String Generate() {
return "Я человек простой, стихов не пишу";
}
}
Зарегистрируем класс в конфигурационном файле (сразу после первого бина)
<bean id="LyricistBean2" class="spring.impls.SimpleMan"/>
Пробуем создать
Lyricist lyr1 = context.getBean("LyricistBean2", Lyricist.class);
System.out.println(lyr1.Generate());
System.out.println(lyr1.hashCode());
Lyricist lyr2 = context.getBean("LyricistBean2", Lyricist.class);
System.out.println(lyr2.Generate());
System.out.println(lyr2.hashCode());
Гражданин все время один и тот же. Непорядок…
Изменим регистрацию бина в конфигурационном файле, добавив волшебное слово scope=«prototype»
В итоге файл srcmainresourcesApplicationContext.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" scope="singleton"/>
<bean id="LyricistBean2" class="spring.impls.SimpleMan" scope="prototype"/>
</beans>
Теперь все в порядке. Граждане каждый раз разные. А Пушкин всегда один.
Внимательные заметили, что в первом бине добавилась настройка scope=«singleton», но это настройка используется по умолчанию, поэтому ее можно и не писать.
На сегодня все. Если данный пост пройдет премодерацию, а у меня появятся время и силы, будет продолжение про AOP, JDBC, транзакции, MVC и прочие премудрсти.
С уважением, Владимир
Автор: kvn_2001