Одно из распространенных заблуждений, связанных с Java-приложениями на основе Spring, заключается в том, что они требуют огромного количества настроек, прежде чем можно будет даже начать работу над реальной проблемой домена, которую приложение должно решать. Это происходит главным образом из-за конфигураций XML, которые уже были значительно сокращены с аннотациями. Но все же, если вы хотите настроить веб-приложение как можно быстрее без конфигурационных файлов Spring (XML), вам необходимо загрузить и настроить веб-сервер, настроить соединение с базой данных, а затем написать все необходимые компоненты, постоянство. xml для hibernate, web.xml и т. д. Поскольку на самом деле вы хотели написать код для решения своей собственной проблемы, вы начинаете спрашивать себя, действительно ли это так сложно !?
Spring Boot призван решить проблемы, перечисленные выше, и обеспечить быструю загрузку приложений Spring. Важно понимать, что Spring Boot не является инструментом генерации кода. Скорее, это можно рассматривать как экономящее время соглашение, включающее автоконфигурацию микроконтейнеров с классами путей передачи классов. Например, если у вас есть зависимость Jetty в пути к классам, он создаст экземпляр встроенного сервера Jetty и запустит на нем ваше приложение. Если нет зависимости от веб-сервера, он будет запускаться как стандартное приложение Java.
Как это работает
Spring Boot запускает приложение из класса, аннотируемого @ EnableAutoConfiguration . Вот один простой пример:
@EnableAutoConfiguration
public class Application
{
public static void main(String[] args)
{
SpringApplication.run(Application.class, args);
}
}
Ниже вы можете увидеть жизненный цикл Spring Boot более подробно:
Фаза инициализации
На этапе инициализации Spring Boot проверяет, должно ли приложение работать в веб-среде, на основании зависимостей, найденных в его пути к классам. Он в основном сканирует путь классов приложений для так называемых типов веб-среды, таких как Servlet и ConfigurableWebApplicationContext . Если они действительно находятся в пути к классам, Spring Boot предполагает, что разработчик хочет запустить его как веб-приложение. После этого все реализации ApplicationListener, определенные внутри META-INF / spring.factories будут созданы экземпляры файлов по всему пути к классам приложения, чтобы они могли быть уведомлены с соответствующими событиями в течение жизненного цикла приложения позже. К ним относятся, по крайней мере, те реализации слушателя, которые уже определены в самом Spring Boot:
- DelegatingApplicationContextInitializer — загружает и применяет инициализаторы, указанные в context.initializer.classes в application.properties.
- ContextIdApplicationContextInitializer — устанавливает идентификатор контекста приложения на основе различных свойств. Для более подробной информации обратитесь к документации.
После этого реализации ApplicationContextInitialiser загружаются аналогичным образом. Они также могут быть определены в файлах META-INF / spring.factories в пути к классам приложения. По крайней мере, те реализации, которые уже определены в самой Spring Boot, включены:
- ParentContextCloserApplicationListener — Слушатель, который закрывает контекст приложения, если его родитель закрыт
- VcapApplicationListener — Слушатель для приложений VCAP (Cloud Foundry)
- FileEncodingApplicationListener — ApplicationListener, который останавливает запуск приложения, если кодировка системного файла не соответствует ожидаемому значению, установленному в среде. По умолчанию это не имеет никакого эффекта, но если вы установите spring.mandatory_file_encoding (или какой-либо из вариантов camelCase или UPPERCASE этого) на имя кодировки символов (например, «UTF-8»), тогда этот инициализатор вызывает исключение, когда файл file.encoding System свойство не равно ему.
- ConfigFileApplicationListener — прослушиватель, отвечающий за загрузку свойств приложения при запуске приложения Spring Boot.
- DelegatingApplicationListener — регистрирует все реализации ApplicationListener, определенные в файле application.properties, в свойстве context.listener.classes . Например, context.listener.classes = mypackage.MyApplicationListener .
- LiquibaseServiceLocatorApplicationListener — заменяет liquibase ServiceLocator версией, которая работает с исполняемыми архивами Spring Boot.
- ClasspathLoggingApplicationListener — регистрирует путь к классам в ApplicationStartedEvent и ApplicationFailedEvent .
- LoggingApplicationListener — Настраивает структуру ведения журнала и сканирует logback и log4j в пути к классам. Логбэк имеет приоритет и по умолчанию включен в зависимости стартерной загрузки. Итак, чтобы использовать log4j, нужно исключить logback, как показано ниже:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
Приложение запущено
После вызова SpringApplication # run (..) будут реализованы реализации интерфейса SpringApplicationRunListener . Цель этих прослушивателей — вызываться на разных этапах метода run ( запущен , environmentPrepared , contextPrepared , contextLoaded , закончен), и единственной реализацией этого интерфейса версии 1.1.6 является EventPublishingRunListener . Эта реализация затем регистрирует все реализации ApplicationListener, загруженные в приложение. Для реализации пользовательского слушателя можно использовать AddListener из SpringApplication или добавить его в Свойство context.listener.classes . Попытка реализовать SpringApplicationRunListener для прослушивания жизненного цикла Spring Boot не удастся, поскольку реализации этого интерфейса будут загружены только из META-INF / spring.factories . Таким образом, способ получить доступ к жизненному циклу Spring Boot состоит в реализации ApplicationListener, в который EventPublishingRunListener будет публиковать события, соответственно. На этом этапе EventPublishingRunListener публикует событие ApplicationStartedEvent, и все зарегистрированные слушатели могут реагировать на него.
Подготовка среды
На этом этапе среда будет создана. Тип среды создается в следующем порядке:
- Пользовательская среда будет возвращена, если предоставляется setEnvironment .
- StandardServletEnvironment, если веб-зависимости найдены в пути к классам (это уже было проверено на этапе инициализации).
- В противном случае StandardEnvironment будет создано.
После этого EventPublishingRunListener публикует событие ApplicationEnvironmentPreparedEvent .
Создание и подготовка контекста приложения
Как и в случае со средой, тип создаваемого контекста приложения имеет следующий порядок:
- Пользовательский контекст приложения, если предоставляется с setApplicationContextClass .
- ConfigEmbeddedWebApplicationContext, если в пути к классам найдены веб-зависимости.
- AnnotationConfigApplicationContext будет создан.
После этого будет зарегистрирован хук отключения, если это не указано с помощью setRegisterShutdownHook (false) . Реализации ResourceLoader и BeanNameGenerator будут загружены, если они указаны с соответствующими установщиками, и заменят реализации по умолчанию.
В конце этого этапа будут вызваны пользовательские и стандартные инициализаторы и загружены исходные классы. В этот момент контекст приложения подготовлен, и EventPublishingRunListener публикует событие ApplicationPreparedEvent .
Обновление контекста
На этом этапе контекст обновляется, и все компоненты из корневого пакета (один класс с @EnableAutoConfiguration ) будут загружены в контекст. Будут загружены все классы автоконфигурации (определенные в META-INF / spring.factories ), за исключением классов , явно отключенных с помощью @EnableAutoConfiguration (exlude = ExludedClass.class) . Затем они сортируются на основе аннотации @Order . Первыми будут загружены файлы с наивысшим приоритетом: MessageSourceAutoConfiguration , PropertyPlaceholderAutoConfiguration , WebSocketAutoConfiguration , EmbeddedServletContainerAutoConfiguration , DispatcherServletAutoConfiguration,
Образец заявки
Этот пример приложения покажет, сколько можно загрузить с помощью Spring Boot. Мы сделаем простой сервис REST, который показывает различные цитаты. Будут использованы следующие технологии:
- Spring MVC для сервиса REST
- Spring Security для проверки подлинности конечных точек
- Spring Data JPA для доступа к данным
- Flyway Migration tool для создания и заполнения базы данных
- H2 встроенная база данных
Pom.xml файл приведен ниже:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.comsysto</groupId>
<artifactId>spring-boot-sample</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>1.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>1.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.181</version>
</dependency>
</dependencies>
<build>
</build>
</project>
Вы можете видеть, что есть только 5 зависимостей. Если вам нужно веб-приложение, вам просто нужно предоставить зависимость spring-boot-starter-data-web. Вы хотите начать прямо сейчас с JPA. Нет проблем, просто предоставьте зависимость spring-boot-starter-data-jpa . Многие зависимости для одного варианта использования больше не нужны. Таким образом, управление зависимостями также упрощается.
Кроме того, нам не нужен дескриптор web.xml, потому что приложение работает на встроенном веб-сервере (Tomcat по умолчанию). Для запуска веб-сервиса нам нужно только написать класс контроллера, как показано ниже, и Spring Boot развернет его на встроенном Tomcat:
@RestController
public class QuoteController
{
@Autowired
@Qualifier("quoteRepository")
private final QuoteRepository repository;
private final static Quote NONE = new Quote("None");
@Autowired
public QuoteController(QuoteRepository repository)
{
this.repository = repository;
}
@Secured("USER")
@RequestMapping (value = "/api", method = RequestMethod.GET)
public Iterable<Quote> getAll()
{
return repository.findAll();
}
@Secured("USER")
@RequestMapping (value = "/api/{id}", method = RequestMethod.GET)
public Quote getOne(@PathVariable Long id)
{
if (repository.exists(id))
{
return repository.findOne(id);
}
else
{
return NONE;
}
}
}
Spring boot добавляет аутентификацию по умолчанию для веб-сервисов, если обнаруживает Spring Security в пути к классам. Хотя это не так практично, это было настроено в другом классе. Добавление роли «USER» в методы веб-службы отменяет имя пользователя и пароль по умолчанию.
@Configuration
public class SecurityConfiguration extends GlobalAuthenticationConfigurerAdapter
{
@Autowired
@Qualifier("restSecurityProperties")
RestSecurityProperties properties;
@Override
public void init(AuthenticationManagerBuilder builder) throws Exception {
builder.inMemoryAuthentication()
.withUser(properties.username())
.password(properties.password())
.roles("USER");
}
}
Для правильной работы приложения нам нужно создать таблицу в базе данных и заполнить ее. Для этого используется инструмент миграции Flyway. Он сканирует папку db.migration для файла с именем <префикс> <версия> __ <описание> .sql . В нашем случае это V1__init.sql . Вручную нам нужно было бы создать bean-компонент с классом Flyway и прикрепить bean- компонент dataSource в качестве свойства, такого как ниже, и вызвать migrate ():
<bean id="flyway" class="org.flywaydb.core.Flyway" init-method="migrate">
<property name="dataSource" ref="..."/>
...
</bean>
К счастью Spring загрузка создала этот компонент и добавила DataSource к нему. Таким образом, единственной частью, которая требовалась от разработчика, было создание файла миграции, т.е. не требуется никакой конфигурации.
Что касается доступа к данным, Spring boot автоматически настроит любой найденный им класс репозитория и подключит к нему bean-компонент dataSource . Таким образом, разработчику нужно только определить класс Entity и интерфейс репозитория.
@Repository
public interface QuoteRepository extends CrudRepository<Quote, Long>
{
}
@Entity
public class Quote
{
@Id
@GeneratedValue
Long id;
private String quote;
protected Quote() {}
public Quote(String quote)
{
this.quote = quote;
}
public Long getId()
{
return id;
}
public String getQuote()
{
return quote;
}
@Override
public String toString()
{
return "id: " + id + " Quote: " + quote;
}
}
Ну, вот как просто запустить и запустить одно веб-приложение с Spring Boot. Тогда, в старые добрые времена корпоративной java, это считалось полноценным трехуровневым J2EE-приложением. С Spring Boot (благодаря нескольким другим превосходным фреймворкам с открытым исходным кодом, таким как Spring, Spring Data и Flyway в этом случае) почти ничего не остается, кроме автоматической настройки;). В следующем посте моего блога будет рассказано о том, как немного более сложное приложение Spring Batch с большим количеством XML-файлов конфигурации может извлечь выгоду из интеграции в сказочную страну Spring Boot.
In case you’ve become curious and would like to discover which potential for innovative software solutions your company holds, get to know us: either in a first conversation, an individually crafted workshop or at one of our numerouscommunity events!