Конфигурация Spring / Spring Boot или «Создаем ментальный фреймворк для Spring»

С архитектурой приложений часто возникают вопросы. Это касается как приложений пакетной обработки (batch job), веб-приложений, так и приложений с обменом сообщениями (messaging application) и других. Фреймворки, такие как Spring Batch, Spring Webflux и Spring Integration служат ориентиром в процессе принятия решения. Кроме того, существует множество специализированных фреймворков, предназначенных для определенной предметной области. Но в этом посте мы не будем о них говорить, а рассмотрим варианты конфигурации Spring.
Помните, что Spring — это большой мешок с объектами. Чтобы предоставлять сервисы, Spring должен знать, как организованы объекты: как они связаны между собой и как взаимодействуют. Например, Spring может стартовать транзакцию при входе в метод и завершить ее при выходе из метода. Или создать HTTP-эндпоинты, которые вызывают методы контроллеров при поступлении запросов. А также обрабатывать сообщения от брокеров, таких как Apache Kafka, AWS SQS, RabbitMQ и других. Список возможностей Spring можно продолжать и продолжать, но все это предполагает первоначальную регистрацию объектов в Spring.
Spring хранит метамодель ваших объектов — это что-то вроде Java Reflection API. Он знает, какие у классов есть аннотации и конструкторы. Также ему известно о зависимостях конкретного объекта: от каких бинов и типов зависит объект. Ваша задача — помочь ему построить эту метамодель для управления всеми вашими объектами. Например, при возможности управления созданием объектов, можно изменить процесс создания объектов до того, как они будут созданы.
Spring предоставит вам все эти сервисы только в случае, если будет знать, как объекты связаны между собой. Таким образом, идея состоит в том, что вы используете POJO (Plain Old Java Objects), а Spring ищет в них аннотации и использует их для настройки поведения ваших сервисов. Но, конечно, это не сделать без контроля создания объектов.
Spring за кулисами создает новый класс, который расширяет ваш. Делается это либо через создание Java InvocationHandler (JDK-прокси), либо, что бывает чаще, с помощью чего-то вроде CGLIB. Создаваемый класс является подклассом вашего класса. Итак, допустим, у вас есть следующий класс:
class CustomerService < private final JdbcTemplate template; CustomerService (JdbcTemplate jt) < this.JdbcTemplate = jt; >@Transactional public void updateCustomer ( long customerId, String name) < // .. . >>
Например, вам нужен автоматический запуск и завершение транзакции при каждом вызове метода updateCustomer . Чтобы это работало, Spring должен вставить свой код до и после вызова этого метода. За кулисами происходит примерно следующее:
class SpringEnhancedCustomerService extends CustomerService < // Spring provides a reference from the applicationContext of type JdbcTemplate SpringEnhancedCustomerService (JdbcTemplate jt) < super(JdbcTemplate ) ; >@Override public void updateCustomer (long customerId, String name) < // call Java code to start a JDBC transaction super.updateCustomer(customerId, name); // call Java code to stop a JDBC transaction >>
Затем в своем коде вы можете инжектировать ссылку на CustomerService . Сервис вы получите, но это будет не тот класс, который вы создавали. Вместо своего класса у вас будет подкласс. Вот такой фокус — вы просите шляпу, а получаете вместо нее шляпу с кроликом. Это и делает Spring таким мощным.
Итак, Spring должен знать о ваших объектах.
До появления Spring Boot у вас было два стандартных варианта конфигурации: XML и Java. Однако это было давно. В настоящее время XML не приветствуется, и остается Java-конфигурация. Вот пример класса конфигурации:
@Configuration class ServiceConfiguration < @Bean DataSource h2DataSource ()< return . ; >@Bean JdbcTemplate JdbcTemplate (DataSource ds) < return new JdbcTemplate(ds); >@Bean CustomerService customerService (JdbcTemplate jdbcTemplate) < return new CustomerService (jdbcTemplate); >>
Здесь создается три объекта и они явно связываются между собой. Spring при старте ищет классы с аннотацией @Configuration , вызывает все методы, аннотированные @Bean , сохраняет все возвращаемые значения в контекст и делает их доступными для инъекции. Если метод принимает параметры, то он ищет другой метод, который возвращает значение нужного типа, и сначала вызывает его. Затем это значение инжектируется в метод через параметр. Если метод ранее уже вызывался для какой-то другой инъекции, то используется уже созданный экземпляр.
Преимущество такого подхода в его явности: вся информация о том, как ваши объекты связаны между собой, находится в одном месте — в классах конфигурации. Как вы заметили, информация о ваших классах присутствует в двух разных местах: в самом классе и в классе конфигурации.
Поэтому можно использовать другой, менее явный подход: сканирование компонентов (component-scanning). В этом случае Spring ищет классы в classpath с аннотациями стереотипов, таких как @Component или @Controller . Все аннотации стереотипов в конечном счете аннотируются @Component . Аннотация @Component — самая общая. Если вы посмотрите на @Controller , он аннотирован @Component . Если вы посмотрите на @RestController , то он тоже будет аннотирован @Controller . Класс, аннотированный @RestController , по-прежнему обрабатывается как минимум как класс, аннотированный @Component . Специализированные аннотации уточняют функциональность, но они по-прежнему остаются наследниками аннотации @Component , а не альтернативой ей.
Итак, кажется, описывать класс CustomerService в классе конфигурации будет лишним. В конце концов, если Spring знает только об этом классе, он дальше сам может разобраться в его связях, не так ли? Можно взглянуть на конструктор и увидеть, что для создания экземпляра CustomerService потребуется ссылка на JdbcTemplate , который определен в другом месте.
Сканирование компонентов это и делает. Вы можете добавить на класс аннотацию @Service — еще одну стереотипную аннотацию, помеченную @Component , — а затем удалить @Bean -метод в классе конфигурации. Spring автоматически создаст сервис и предоставит необходимые зависимости. Он также создаст подкласс для реализации необходимых сервисов.
Мы делаем успехи, удаляя все больше бойлерплейта. Но как насчет DataSource и JdbcTemplate? Они нам нужны, но не описывать же их каждый раз заново? В этом нам поможет Spring Boot. Для принятия решения о создании класса или вызова @Bean -метода Spring Boot использует аннотацию @Condition для декорирования классов с @Component или @Configuration . Решение может приниматься и на основе окружения. Например, у вас в classpath есть H2 (встраиваемая SQL-база данных) и библиотека spring-jdbc, которая содержит класс JdbcTemplate . При наличии этих классов в classpath можно сделать вывод о том, что вам нужен встроенный SQL DataSource и что вы хотите связать экземпляр JdbcTemplate с этим источником данных. Теперь можно полностью отказаться от класса @Configuration !
Мы рассмотрели основы конфигурации Spring IoC-контейнера. Можно было бы пойти намного дальше и поговорить об аспектно-ориентированном программировании (АОП), автоконфигурации и многом другом. Но об этом не сегодня. Цель этого поста — объяснить, когда применять тот или иной вид конфигурации.
Материал подготовлен в рамках курса «Разработчик на Spring Framework». Если вам интересно узнать подробнее о формате обучения и программе, познакомиться с преподавателем курса — приглашаем на день открытых дверей онлайн. Регистрация здесь.
- spring
- spring boot
- Spring Framework
- ментальный фреймворк
- Конфигурация Spring
Spring: в поисках контекста
Пару месяцев назад в моем профиле был опубликован подробный пост по загрузке классов на JVM. После этого доклада мои коллеги задались хорошим вопросом: а какой механизм использует Spring для разбора конфигураций и как он загружает классы из контекста?

После многих часов дебага спринговых исходников мой коллега экспериментальным путём докопался до той самой простой и понятной правды.
Немного теории
Сразу определим, что ApplicationContext — это главный интерфейс в Spring-приложении, который предоставляет информацию о конфигурации приложения.
Перед тем, как перейти непосредственно к демонстрации, взглянем на этапы формирования ApplicationContext:

В этом посте разберем первый этап, так как нас интересует именно чтение конфигураций и создание BeanDefinition.
BeanDefinition — это интерфейс, который описывает бин, его свойства, аргументы конструктора и другую метаинформацию.
Что касается конфигурации самих бинов, у Spring есть 4 способа конфигурации:
- Xml конфигурация — ClassPathXmlApplicationContext(”context.xml”);
- Groovy конфигурация — GenericGroovyApplicationContext(”context.groovy”);
- Конфигурация через аннотации с указанием пакета для сканирования — AnnotationConfigApplicationContext(”package.name”);
- JavaConfig — конфигурация через аннотации с указанием класса (или массива классов) помеченного аннотацией @Configuration — AnnotationConfigApplicationContext(JavaConfig.class).
Xml конфигурация
За основу берем простой проект:
public class SpringContextTest< private static String classFilter = "film."; public static void main(String[] args)< printLoadedClasses(classFilter); /* Classloader: sun.misc.Launcher$AppClassLoader@18b4aac2 All - 5 : 0 - Filtered /* doSomething(MainCharacter.num); doSomething(FilmMaker.class); printLoadedClasses(classFilter); /* Classloader: sun.misc.Launcher$AppClassLoader@18b4aac2 class film.MainCharacter class film.FilmMaker All - 7 : 2 - Filtered /*
Здесь следует немного пояснить, какие методы и для чего используются:
- printLoadedClasses(String… filters) — метод выводит в консоль название загрузчика и загруженных JVM классов из пакета, переданного как параметр. Дополнительно есть информация о количестве всех загруженных классов;
- doSomething(Object o) — метод, который делает примитивную работу, но не позволяет исключить упомянутые классы в процессе оптимизации при компиляции.
11 public class SpringContextTest< 12 private static String calssFilter = "film."; 13 14 public static void main(String[] args)< 15 16 printLoadedClasses(classFilter); 17 /* Classloader: sun.misc.Launcher$AppClassLoader@18b4aac2 18 All - 5 : 0 - Filtered /* 19 doSomething(MainCharacter.num); doSomething(FilmMaker.class); 20 printLoadedClasses(classFilter); 21 /* Classloader: sun.misc.Launcher$AppClassLoader@18b4aac2 22 class film.MainCharacter 23 class film.FilmMaker 24 All - 7 : 2 - Filtered /* 25 ApplicationContext context = new ClassPathXmlApplicationContext( 26 configLocation: "applicationContext.xml"); 27 printLoadedClasses(classFilter);
В 25 строке идет объявление и инициализация ApplicationContext через конфигурацию Xml.
Конфигурационный Xml-файл выглядит следующим образом:
При конфигурации бина указываем реально существующий class. Обратите внимание на заданное свойство lazy-init=”true”: в этом случае бин будет создаваться только после запроса его из контекста.
Смотрим, как Spring при поднятии контекста разрулит ситуацию с классами, объявленными в конфигурационном файле:
public class SpringContextTest < private static String classFilter = "film."; public static void main(String[] args) < printLoadedClasses(classFilter); /* Classloader: sun.misc.Launcher$AppClassLoader@18b4aac2 All - 5 : 0 - Filtered /* doSomething(MainCharacther.num); doSomething(FilmMaker.class); printLoadedClasses(classFilter); /* Classloader: sun.misc.Launcher$AppClassLoader@18b4aac2 class film.MainCharacter class film.FilmMaker All - 7 : 2 - Filtered /* ApplicationContext context = new ClassPathXmlApplicationContext( configLocation: "applicationContext.xml"); printLoadedClasses(classFilter); /* Classloader: sun.misc.Launcher$AppClassLoader@18b4aac2 class film.MainCharacter class film.FilmMaker class film.Villain All - 343 : 3- Filtered /*
Разберемся с деталями Xml конфигурации:
— Чтением файла конфигурации занимается класс XmlBeanDefinitionReader, который реализует интерфейс BeanDefinitionReader;
— XmlBeanDefinitionReader на входе получает InputStream и загружает Document через DefaultDocumentLoader:
Document doc = doLoadDocument(inputSource, resource); return registerBeanDefinitions(doc, resource);
— После этого каждый элемент этого документа обрабатывается и, если он является бином, создается BeanDefinition на основе заполненных данных (id, name, class, alias, init- method, destroy-method и др.):
> else if (delegate.nodeNameEquals(ele, "bean")) < this.processBeanDefinition(ele, delegate);
— Каждый BeanDefinition помещается в Map, который хранится в классе DefaultListableBeanFactory:
this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName);
В коде Map выглядит следующим образом:
/** Map of bean definition objects, keyed by bean name */ private final Map beanDefinitionMap = new ConcurrentHashMap(64);
Теперь в том же конфигурационном файле добавим еще одно объявление бина с классом film.BadVillain:
Смотрим, что получится, если распечатать список созданных BeanDefenitionNames и загруженные классы:
ApplicationContext context = new ClassPathXmlApplicationContext( configLocation: "applicationContext.xml"); System.out.println(Arrays.asList(context.getBeanDefinitionNames())); printLoadedClasses(calssFilter);
Несмотря на то, что класса film.BadVillain, указанного в конфигурационном файле, не существует, Spring отрабатывает без ошибок:
ApplicationContext context = new ClassPathXmlApplicationContext( configLocation: "applicationContext.xml"); System.out.println(Arrays.asList(context.getBeanDefinitionNames())); // [goodVillain, badVillain] printLoadedClasses(calssFilter); /* Classloader: sun.misc.Launcher$AppClassLoader@18b4aac2 class film.MainCharacter class film.FilmMaker class film.Villain All - 343 : 3- Filtered /*
Cписок BeanDefenitionNames содержит 2 элемента; то есть, те 2
BeanDefinition, сконфигурированные в нашем файле, были созданы.
Конфигурации обоих бинов, по сути, одинаковы. Но, при этом существующий класс загрузился, никаких проблем не возникло. Из чего можно сделать вывод, что попытка загрузить несуществующий класс также была, но провальная попытка ничего не сломала.
Попытаемся получить еще и сами бины по их именам:
ApplicationContext context = new ClassPathXmlApplicationContext( configLocation: "applicationContext.xml"); System.out.println(Arrays.asList(context.getBeanDefinitionNames())); // [goodVillain, badVillain] System.out.println(context.getBean( name: "goodVillain")); System.out.println(context.getBean( name: "badVillain"));

Если в первом случае был получен валидный бин, то во втором случае прилетел exception.
Обратите внимание на stack trace: сработала отложенная загрузка классов. Выполняется обход всех загрузчиков классов в попытке найти искомый класс среди загруженных ранее. И после того, как нужный класс не был найден, с помощью вызова метода Utils.forName, происходит попытка найти несуществующий класс по имени, что привело к получению закономерной ошибки.
При поднятии контекста загрузился только один класс, при этом попытка загрузки несуществующего файла не привела к ошибке. Почему так произошло?
Всё потому, что мы прописали lazy-init:true и запретили Spring создавать экземпляр бина, где и генерируется полученный ранее exception. Если убрать это свойство из конфигурации либо изменить его значение lazy-init:false, то описанная выше ошибка также вылетит, но не будет проигнорирована и приложение остановиться. В нашем случае контекст был проинициализирован, но мы не смогли создать экземпляр бина, т.к. указанный класс не был найден.
Groovy конфигурация
При конфигурации контекста с помощью Groovy-файла, необходимо сформировать GenericGroovyApplicationContext, который принимает на вход строку с конфигурацией контекста. Чтением контекста в данном случае занимается класс GroovyBeanDefinitionReader. Эта конфигурация работает по сути так же, как и Xml, только с Groovy-файлами. К тому же, GroovyApplicationContext нормально работает и с Xml-файлом.
Пример простого конфигурационного Groovy-файла:
beans < goodOperator(film.Operator)bean.lazyInit = 'true' > name = 'Good Oleg' > badOperator(film.BadOperator) bean.lazyInit = 'true' > name = 'Bad Oleg' / > > >
Пробуем проделать то же самое, что и с Xml:

Ошибка вылетает сразу: Groovy так же, как и Xml, создает BeanDefenition'ы, но в данном случае постпроцессор сразу выдаёт ошибку.
Конфигурация через аннотации с указанием пакета для сканирования или JavaConfig
Данная конфигурация отличается от двух предыдущих. В конфигурация через аннотации используется 2 варианта: JavaConfig и аннотация над классами.
Здесь используется один и тот же контекст: AnnotationConfigApplicationContext(“package”/JavaConfig.class). Работает он в зависимости от того, что было передано в конструктор.
В контексте AnnotationConfigApplicationContext есть 2 приватных поля:
- private final AnnotatedBeanDefinitionReader reader (работает с JavaConfig);
- private final ClassPathBeanDefinitionScanner scanner (сканирует пакет).
- Регистрация всех @Configuration-файлов для дальнейшего парсинга;
- Регистрация специального BeanFactoryPostProcessor, а именно BeanDefinitionRegistryPostProcessor, который при помощи класса ConfigurationClassParser парсит JavaConfig и создает BeanDefinition.
@Configuration public class JavaConfig < @Bean @Lazy public MainCharacter mainCharacter()< MainCharacter mainCharacter = new MainCharacter(); mainCharacter.name = "Patric"; return mainCharacter; >>
public static void main(String[] args) < ApplicationContext javaConfigContext = new AnnotationConfigApplicationContext(JavaConfig.class); for (String str : javaConfigContext.getBeanDefinitionNames())< System.out.println(str); >printLoadedClasses(classFilter);
Создаем конфигурационный файл с максимально простым бином. Смотрим, что загрузится:

Если в случае с Xml и Groovy загрузилось столько BeanDefinition, сколько было объявлено, то в данном случае в процессе поднятия контекста загружаются как объявленные, так и дополнительные BeanDefinition. В случае реализации через JavaConfig все классы загружаются сразу, в том числе и класс самого JavaConfig, так как он сам является бином.
Еще один момент: в случае с Xml и Groovy конфигурациями загрузилось 343 файла, здесь же произошла более “тяжелая” загрузка количеством 631 доп файл.
Этапы работы ClassPathBeanDefinitionScanner:
- По указанному пакету определяется список файлов для сканирования. Все файлы попадают в директории;
- Сканер проходит по каждому файлу, получает InputStream и сканирует при помощи класса org.springframework.asm.ClassReader.class;
- На 3-ем этапе сканер проверяет, проходят ли найденные объекты по фильтрам аннотации org.springframework.core.type.filter.AnnotationTypeFilter. По умолчанию Spring ищет классы, которые помечены аннотацией Component либо любой другой аннотацией, которая включает в себя Component;
- Если проверка проходит успешно, создаются и регистрируются новые BeanDefinition.
Рассмотрим работу сканера на простом примере.
Создаем собственную аннотацию для поиска соответствующих классов:
import org.springframework.stereotype.Component import java.lang.annotation.*; @Target() @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface MyBeanLoader< String value() default "";
Создаем 2 класса: один со стандартной аннотацией Component, второй — с кастомной аннотацией:
@Component public class MainCharacter
MyBeanLoader("makerFilm") @Lazy public class FilmMaker
В результате получаем сформированные BeanDefinition для этих классов и успешно загруженные классы.
ApplicationContext annotationConfigContext = new AnnotationConfigApplicationContext(. basePackages: "film"); for (String str : annotationConfigContext.getBeanDefinitionNames()) < System.out.println(str); >printLoadedClasses(classFilter);

Вывод
Из всего вышесказанного на поставленные вопросы можно ответить следующим образом:
-
Какой механизм использует Spring для разбора конфигураций?
Обзор модулей Spring для Java
Рассматриваем основные модули Spring для Java и узнаём, какие у них особенности и для чего их можно использовать.
Рассказывает Мария Багулина
Spring для Java — обширная платформа для создания веб-проектов на Java, состоящая из множества независимых модулей (проектов) для разных задач: от простых веб-приложений до Big Data. Мы рассмотрим, что дают эти модули, какие их основные особенности и для чего их можно использовать.
Что такое Spring?
Spring возник в 2003 году в виде облегчённого аналога платформы для корпоративных приложений Java Enterprise. Он позиционируется как простая в использовании платформа для веб-приложений. Spring поддерживает несколько языков JVM: Java, Kotlin и Groovy.
Spring состоит из большого числа модулей. Среди них есть модули-стартеры, без которых Spring-приложение просто не запустится, а есть также вспомогательные проекты, добавляющие в приложение определённую функциональность: например Spring Data Flow для потоковой обработки данных, Security для безопасности или Cloud для распределённых систем. Такая структура позволяет разработчикам эффективно создавать и поддерживать приложения, используя только нужные инструменты.
Остановимся более подробно на основных модулях Spring и узнаем, для чего их можно использовать.
Несколько слов о Spring Framework
Spring Framework — ядро платформы Spring. Framework неявно используется другими компонентами Spring, например MVC и WebFlux, обеспечивая фундаментальные инструменты для различных архитектур приложений. Мы не будем рассматривать его как отдельный модуль Spring, но перечислим основные характеристики и особенности.
Spring Framework включает:
- Основные технологии: внедрение зависимостей, события, ресурсы, i18n, проверка, связывание данных, преобразование типов, SpEL, AOP.
- Инструменты тестирования: mock-объекты, TestContext, Spring MVC Test, WebTestClient.
- Доступ к данным: транзакции, поддержка DAO, JDBC, ORM, Marshalling XML.
- Интеграцию: удалённое взаимодействие, JMS, JCA, JMX, электронная почта, задачи, планирование, кеш.
Spring Boot
Spring Boot — комплексный фреймворк для создания и запуска приложений с минимальными усилиями и настройками. Этот модуль делится на два стека: основанный на API сервлетов Spring MVC и реактивный Spring WebFlux.
Spring WebFlux — веб-платформа, созданная, чтобы по максимуму использовать преимущества современных многоядерных процессоров и обрабатывать огромное количество одновременных подключений.
Spring MVC построен на API сервлетов и использует архитектуру синхронного блокирующего ввода-вывода с моделью «один запрос на поток».
В Spring Boot также можно опционально подключить библиотеку Reactor для создания реактивных систем на JVM.
Характеристики
- Встраивание контейнеров Tomcat, Jetty или Undertow напрямую без развёртывания WAR-файлов.
- Готовые стартовые зависимости, упрощающие конфигурацию сборки.
- Возможность сконфигурировать проект прямо в браузере с помощью Spring Initializr.
- Автоматическая настройка сторонних библиотек (по возможности).
- Готовые к работе функции, такие как сбор метрик, проверка работоспособности и использование внешней конфигурации.
- Нет кодогенерации и не требуется конфигурация XML — всё конфигурируется через аннотации.
Для чего используется
Вместе со Spring Boot в проектах обычно используются Spring Security и Cloud. С помощью Spring Boot можно создавать:
- микросервисы;
- реактивные системы;
- веб-приложения.
Что почитать и с чего начать
Для скоростного погружения в Spring Boot пройдитесь по руководству по быстрому запуску. Также в официальной документации можно найти гайд по созданию приложения с помощью Spring Boot и туториал для написания веб-службы RESTful.
Spring Data
Модуль обеспечивает приложениям доступ к данным через реляционные и нереляционные базы данных (БД), map-reduce фреймворки и облачные сервисы. Spring Data содержит множество подпроектов, предназначенных для определённых СУБД. Среди них есть, например, MySQL, MongoDB, Redis и многие другие. Также можно использовать подмодули, разработанные сообществом Spring для более специфичных баз данных вроде ArangoDB, Google Datastore, Microsoft Azure Cosmos DB и других.
Основной механизм, реализуемый в Spring Data — репозиторий. Это набор интерфейсов, использующих JPA Entity для взаимодействия с данными.
Характеристики
- Настраиваемое отображение сущностей в БД на Java-объекты.
- Создание динамических запросов в базу данных через сигнатуру метода интерфейса репозитория.
- Базовые классы для различных задач.
- Прозрачный аудит объектов.
- Возможность интегрировать собственный код репозитория.
- Простая интеграция со Spring через JavaConfig, а также кастомных пространств имён XML.
- Расширенная интеграция с контроллерами Spring MVC.
Для чего используется
Spring Data используется везде, где нужен доступ к данным, и легко интегрируется с другими модулями Spring.
Что почитать и с чего начать
Обо всех модулях Spring Data можно почитать в официальной документации.
Spring Cloud
Со Spring Cloud вы сможете легко и быстро создавать шаблоны в распределённых системах. Из примеров таких шаблонов: управление конфигурацией, обнаружение сервисов, интеллектуальная маршрутизация, микропрокси, одноразовые токены и многое другое.
Шаблоны, созданные с помощью Spring Cloud, будут хорошо работать в любой распределённой среде, включая ваш собственный ноутбук, центры обработки данных и PaaS-платформы, такие как Cloud Foundry.
Spring Cloud также состоит из множества подпроектов для разных целей. Так, Spring Cloud Azure интегрирует Spring со службами Azure, Spring Cloud Stream используется для создания управляемых событиями микросервисов (event-driven microservices) и так далее.
Характеристики
- Распределённая / версионная конфигурация.
- Регистрация и обнаружение сервисов.
- Маршрутизация.
- Связь между сервисами (service-to-service calls).
- Балансировка нагрузки.
- Выбор лидера и состояние кластера.
- Распределённый обмен сообщениями.
Для чего используется
Spring Cloud содержит много полезных инструментов для микросервисов и распределённых систем.
Что почитать и с чего начать
Посмотрите большой гайд для начинающих, попробуйте создать микросервис с балансировкой нагрузки и почитайте документацию с примерами.
Spring Cloud Data Flow
Spring Cloud Data Flow нужен приложениям, в которых используется потоковая передача и пакетная обработка данных.
Фреймворк поддерживает ряд готовых кейсов обработки данных, среди которых ETL, потоковая обработка событий и прогнозная аналитика.
Характеристики
- Развёртывание приложений на платформах Cloud Foundry и Kubernetes.
- Готовые приложения для различных сценариев интеграции и обработки данных.
- Настраиваемые приложения, ориентированные на связующее ПО или службы данных.
- Простой потоковый конвейер DSL, чтобы указывать, какие приложения развёртывать и как подключать выходы и входы.
- Графический редактор для интерактивного построения конвейеров данных и мониторинга метрик с помощью Wavefront, Prometheus, Influx DB или других систем.
- REST API для создания и развёртывания конвейеров данных с возможностью работы из командной строки.
Для чего используется
Spring Cloud Data Flow подойдёт для создания конвейеров потоковой обработки данных — например, чтобы пересылать какие-либо данные в базу и затем удобно анализировать их.
Что почитать и с чего начать
Попробуйте создать микросайт с помощью Spring Cloud Data Flow и ознакомиться с примерами использования.
Spring Security
Spring Security — среда аутентификации, авторизации и контроля доступа. Это стандартный фреймворк, который используется для защиты приложений на основе Spring.
Spring Security предоставляет базовые функции безопасности, которые можно легко расширить для ваших собственных нужд.
Характеристики
- Аутентификация и авторизация пользователей.
- Защита от атак, таких как фиксация сессии, кликджекинг, подделка межсайтовых запросов и так далее.
- Возможность интеграции с Servlet API.
- Опционально подключаемый модуль Spring Web MVC.
Для чего используется
Модуль Security нужен, чтобы обеспечить проверку безопасности и защитить приложение от атак.
Что почитать и с чего начать
На официальном сайте есть небольшое руководство по защите веб-приложения, более подробный гайд с объяснением всех функций и особенностей Spring Security, а также раздел в документации.
Spring Integration
Spring Integration позволяет облегчить обмен сообщениями в приложениях на основе Spring, поддерживает интеграцию с внешними системами и даёт инструменты для обработки данных из разных источников. Один из подпроектов Spring Cloud, Spring Cloud Stream, использует Spring Integration как движок для микросервисов, управляемых событиями.
Характеристики
- Много шаблонов для интеграции приложений предприятия.
- Интеграция с внешними системами.
- Веб-сервисы (SOAP и REST).
- Обширная поддержка JMX.
- MBeans-компоненты.
Для чего используется
Spring Integration подключается к проекту, если вам нужно связать POJO (Plain Old Java Object) с помощью парадигмы обмена сообщениями без внедрения зависимостей (DI). Также Integration позволяет взаимодействовать с внешними системами с помощью адаптеров каналов и шлюзов. Адаптеры каналов используются для односторонней интеграции (отправка или получение), а шлюзы — для сценариев запроса / ответа (входящего или исходящего).
Что почитать и с чего начать
Посмотрите небольшое руководство по созданию приложения, использующего Spring Integration для извлечения данных, их обработки и записи в файл. Также можете изучить более 50 примеров.
Spring Batch
Spring Batch — платформа для разработки пакетных приложений. Spring Batch подойдёт как для простых, так и для более сложных проектов — платформа легко масштабируется и может обрабатывать большие объёмы информации.
Характеристики
- Управление транзакциями.
- Обработка на основе фрагментов данных.
- Декларативный ввод / вывод.
- Веб-интерфейс администрирования (Spring Cloud Data Flow).
Для чего используется
Spring Batch подойдёт для приложений с многократно используемыми функциями, чтобы обрабатывать большие объёмы записей. Среди таких функций — ведение логов и трассировка, управление транзакциями, статистика обработки заданий, перезапуск и пропуск заданий, управление ресурсами и другие.
Что почитать и с чего начать
Гайд по созданию базовой пакетной службы и более 20 примеров использования Spring Batch.
…И ещё немного
Мы перечислили лишь ключевые модули Spring. На самом деле их гораздо больше: например, есть ещё Spring for Android для создания Android-приложений, Spring CredHub для взаимодействия с CredHub-сервером, Spring LDAP и многие другие.
С полным списком проектов Spring можно ознакомиться на официальном сайте.
Понимание Application Context
ApplicationContext - это главный интерфейс в Spring-приложении, который предоставляет информацию о конфигурации приложения. Он доступен только для чтения во время выполнения, но может быть перезагружен при необходимости и поддержке приложением. Число классов, реализующих ApplicationContext интерфейс, доступны для различных параметров конфигурации и типов приложений.
- Фабричные методы бина для доступа к компонентам приложения
- Возможность загружать файловые ресурсы в общем виде
- Возможность публиковать события и регистрировать обработчики на них
- Возможность работать с сообщениями с поддержкой интернационализации
- Наследование от родительского контекста
Доступность контекста приложения
Ниже представлено несколько способов получения ссылки на контекст приложения. Вы можете реализовать ApplicationContextAware как показано на примере ниже:
package hello; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class A implements ApplicationContextAware < private ApplicationContext applicationContext; public void setApplicationContext(ApplicationContext applicationContext) < this.applicationContext = applicationContext; >>
Вы также можете использовать аннотацию @Autowired для введения ссылки напрямую в ваш класс:
package hello; import org.springframework.beans.factory.annotation.Autowired; public class B
С оригинальным текстом урока вы можете ознакомиться на spring.io.
Учебные материалы
- Создание приложений с Spring Boot
- Аутентификация пользователя в LDAP