«Руководства по использованию»
Этот раздел содержит ответы на некоторые распространенные вопросы типа «как это сделать…», которые часто возникают при использовании Spring Boot. Охват не исчерпывающий, но охватывает довольно много аспектов.
Если у вас есть специфическая проблема, которая здесь не рассматривается, вы можете проверить stackoverflow.com, чтобы посмотреть, уже ли кто-то предоставил ответ. Это также отличное место для задавания новых вопросов (пожалуйста, используйте тег spring-boot).
Мы также с удовольствием расширим этот раздел. Если вы хотите добавить «как это сделать», отправьте нам pull request.
1. Приложение Spring Boot
Этот раздел включает темы, напрямую относящиеся к приложениям Spring Boot.
1.1. Создание собственного анализатора ошибок
FailureAnalyzer — отличный способ перехватить исключение при запуске и преобразовать его в удобочитаемое сообщение, заключенное в FailureAnalysis. Spring Boot предоставляет такой анализатор для исключений, связанных с контекстом приложения, валидациями JSR-303 и другими. Вы также можете создать свой собственный.
AbstractFailureAnalyzer — это удобное расширение FailureAnalyzer, которое проверяет наличие указанного типа исключения в исключении для обработки. Вы можете расширить его, чтобы ваша реализация могла обработать исключение только тогда, когда оно действительно присутствует. Если по какой-либо причине вы не можете обработать исключение, верните null, чтобы дать другой реализации возможность обработать исключение.
Реализации FailureAnalyzer должны быть зарегистрированы в META-INF/spring.factories. Следующий пример регистрирует ProjectConstraintViolationFailureAnalyzer:
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.ProjectConstraintViolationFailureAnalyzer Если вам нужен доступ к BeanFactory или Environment, ваша FailureAnalyzer может реализовать соответственно BeanFactoryAware или EnvironmentAware. |
1.2. Устранение неполадок в автоматической конфигурации
Автоматическая конфигурация Spring Boot старается сделать всё наилучшим образом, но иногда возникают ошибки, и определить причину может быть сложно.
В любом приложении Spring Boot доступен очень полезный ConditionEvaluationReport. Вы можете увидеть его, если включить DEBUG вывод журналов. Если вы используете spring-boot-actuator (см. главу «Актуатор»), также есть конечная точка conditions, которая отображает отчёт в формате JSON. Используйте эту конечную точку для отладки приложения и просмотра функций, добавленных (и не добавленных) Spring Boot во время выполнения.
Множество дополнительных вопросов можно ответить, изучив исходный код и JavaDoc. При чтении кода помните следующие правила:
-
Ищите классы с именем
*AutoConfigurationи читайте их исходный код. Обратите особое внимание на аннотации@Conditional*, чтобы узнать, какие функции они включают и когда. Добавьте--debugв командную строку или системную переменную-Ddebug, чтобы получить в консоли журнал всех принятых решений по автоматической конфигурации в вашем приложении. В работающем приложении с активированным актуатором посмотрите на конечную точкуconditions(/actuator/conditionsили эквивалент JMX) для получения той же информации. -
Ищите классы, которые являются
@ConfigurationProperties(такие какServerProperties) и читайте доступные внешние параметры конфигурации. Аннотация@ConfigurationPropertiesимеет атрибутname, который выступает в качестве префикса для внешних свойств. Таким образом,ServerPropertiesимеетprefix="server", и его свойства конфигурации являютсяserver.port,server.addressи другими. В работающем приложении с активированным актуатором посмотрите на конечную точкуconfigprops. -
Ищите использование метода
bindна классеBinderдля явного извлечения значений конфигурации изEnvironmentлёгким способом. Часто используется с префиксом. -
Ищите аннотации
@Value, которые напрямую привязываются кEnvironment. -
Ищите аннотации
@ConditionalOnExpression, которые включают и выключают функции в ответ на выражения SpEL, обычно вычисляемые с разрешёнными плейсхолдерами изEnvironment.
1.3. Настройка среды или ApplicationContext перед запуском
У SpringApplication есть ApplicationListeners и ApplicationContextInitializers, которые используются для применения настроек к контексту или среде. Spring Boot загружает множество таких настроек для внутреннего использования из META-INF/spring.factories. Существует более одного способа регистрации дополнительных настроек:
-
Программно, на уровне приложения, вызвав методы
addListenersиaddInitializersна объектеSpringApplicationдо его запуска. -
Декларативно, на уровне приложения, установив свойства
context.initializer.classesилиcontext.listener.classes. -
Декларативно, для всех приложений, добавив
META-INF/spring.factoriesи упаковав jar-файл, который все приложения используют как библиотеку.
SpringApplication отправляет некоторые специальные ApplicationEvents слушателям (некоторые даже до создания контекста), а затем регистрирует слушателей для событий, опубликованных ApplicationContext. См. «События и слушатели приложений» в разделе «Функции Spring Boot» для полного списка.
Также можно настроить Environment до обновления контекста приложения, используя EnvironmentPostProcessor. Каждая реализация должна быть зарегистрирована в META-INF/spring.factories, как показано в следующем примере:
org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
Реализация может загружать произвольные файлы и добавлять их в Environment. Например, следующий пример загружает YAML-конфигурационный файл из classpath:
public class MyEnvironmentPostProcessor implements EnvironmentPostProcessor {
private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
Resource path = new ClassPathResource("com/example/myapp/config.yml");
PropertySource<?> propertySource = loadYaml(path);
environment.getPropertySources().addLast(propertySource);
}
private PropertySource<?> loadYaml(Resource path) {
Assert.isTrue(path.exists(), () -> "Resource " + path + " does not exist");
try {
return this.loader.load("custom-resource", path).get(0);
}
catch (IOException ex) {
throw new IllegalStateException("Failed to load yaml configuration from " + path, ex);
}
}
}
class MyEnvironmentPostProcessor : EnvironmentPostProcessor {
private val loader = YamlPropertySourceLoader()
override fun postProcessEnvironment(environment: ConfigurableEnvironment, application: SpringApplication) {
val path: Resource = ClassPathResource("com/example/myapp/config.yml")
val propertySource = loadYaml(path)
environment.propertySources.addLast(propertySource)
}
private fun loadYaml(path: Resource): PropertySource<*> {
Assert.isTrue(path.exists()) { "Resource $path does not exist" }
return try {
loader.load("custom-resource", path)[0]
} catch (ex: IOException) {
throw IllegalStateException("Failed to load yaml configuration from $path", ex)
}
}
}
Environment уже подготовлен со всеми обычными источниками свойств, которые Spring Boot загружает по умолчанию. Поэтому можно получить расположение файла из среды. В предыдущем примере добавляется источник свойств custom-resource в конец списка, чтобы ключ, определённый в любом другом расположении, имел приоритет. Пользовательская реализация может определить другой порядок. |
Хотя использование @PropertySource в вашей @SpringBootApplication может показаться удобным способом загрузки пользовательских ресурсов в Environment, мы не рекомендуем этого делать. Такие источники свойств не добавляются в Environment до тех пор, пока контекст приложения не обновляется. Это происходит слишком поздно для настройки определённых свойств, таких как logging.* и spring.main.*, которые читаются до начала обновления. |
1.4. Построение иерархии ApplicationContext (Добавление родительского или корневого контекста)
Для создания иерархий родительских/дочерних ApplicationContext контекстов можно использовать класс ApplicationBuilder. Подробнее см. «features.html» в разделе «Функции Spring Boot».
1.5. Создание не веб-приложения
Не все приложения Spring должны быть веб-приложениями (или веб-сервисами). Если вы хотите выполнить код в методе main, но также запустить приложение Spring для настройки инфраструктуры, вы можете использовать возможности Spring Boot. SpringApplication меняет свой класс ApplicationContext, в зависимости от того, считает ли он, что ему нужно веб-приложение или нет. Первое, что вы можете сделать, это убрать зависимости, связанные с сервером (например, API сервлетов) из classpath. Если вы этого сделать не можете (например, вы запускаете два приложения из одного кода), вы можете явно вызвать метод setWebApplicationType(WebApplicationType.NONE) на вашем объекте SpringApplication или установить свойство applicationContextClass (через Java API или с помощью внешних свойств). Код приложения, который вы хотите использовать как бизнес-логику, может быть реализован как CommandLineRunner и добавлен в контекст как определение @Bean.
2. Свойства и конфигурация
В этом разделе рассматриваются темы настройки и чтения свойств и параметров конфигурации, а также их взаимодействие с приложениями Spring Boot.
2.1. Автоматическое расширение свойств во время сборки
Вместо того, чтобы жестко кодировать некоторые свойства, которые также указаны в конфигурации сборки вашего проекта, вы можете автоматически расширить их, используя существующую конфигурацию сборки. Это возможно как в Maven, так и в Gradle.
2.1.1. Автоматическое расширение свойств с помощью Maven
Вы можете автоматически расширить свойства из проекта Maven, используя фильтрацию ресурсов. Если вы используете spring-boot-starter-parent, вы можете ссылаться на свои свойства Maven-проекта с помощью @..@ плейсхолдеров, как показано в следующем примере:
app.encoding=@project.build.sourceEncoding@
app.java.version=@java.version@ app:
encoding: "@project.build.sourceEncoding@"
java:
version: "@java.version@" Фильтруется только конфигурация для среды производства (другими словами, фильтрация не применяется к src/test/resources). |
Если вы включите флаг addResources, цель spring-boot:run может добавить src/main/resources непосредственно в класспасс (для целей горячей перезагрузки). Это обойдет фильтрацию ресурсов и данную функцию. Вместо этого вы можете использовать цель exec:java или настроить конфигурацию плагина. Смотрите страницу использования плагина здесь для получения дополнительной информации. |
Если вы не используете родительский стартер, вам необходимо включить следующий элемент внутри элемента <build/> вашего pom.xml:
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources> Вам также необходимо включить следующий элемент внутри <plugins/>:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<configuration>
<delimiters>
<delimiter>@</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin> Свойство useDefaultDelimiters важно, если вы используете стандартные плейсхолдеры Spring (например, ${placeholder}) в вашей конфигурации. Если это свойство не установлено в значение false, они могут быть расширены во время сборки. |
2.1.2. Автоматическое расширение свойств с помощью Gradle
Вы можете автоматически расширить свойства из проекта Gradle, настроив задачу плагина Java processResources, как показано в следующем примере:
tasks.named('processResources') {
expand(project.properties)
} Затем вы можете обратиться к свойствам вашего проекта Gradle, используя плейсхолдеры, как показано в следующем примере:
app.name=${name}
app.description=${description} app:
name: "${name}"
description: "${description}" Метод expand Gradle использует Groovy's SimpleTemplateEngine, который преобразует ${..} токены. Стиль ${..} конфликтует с собственным механизмом подстановки свойств Spring. Для использования плейсхолдеров свойств Spring вместе с автоматическим расширением, экранируйте плейсхолдеры свойств Spring следующим образом: \${..}. |
2.2. Экстернализация конфигурации SpringApplication
Класс SpringApplication имеет геттеры и сеттеры свойств, поэтому вы можете использовать его Java API для изменения поведения приложения. Кроме того, вы можете экстернализировать конфигурацию, задав свойства в файле spring.main.*. Например, в application.properties могут быть следующие настройки:
spring.main.web-application-type=none
spring.main.banner-mode=off spring:
main:
web-application-type: "none"
banner-mode: "off" Тогда баннер Spring Boot не будет выводиться при запуске, и приложение не будет запускать встроенный веб-сервер.
Свойства, определённые во внешней конфигурации, переопределяют и заменяют значения, заданные с помощью Java API, за исключением первичных источников. Первичные источники — это те, которые были предоставлены конструктору SpringApplication:
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.setBannerMode(Banner.Mode.OFF);
application.run(args);
}
}
@SpringBootApplication
object MyApplication {
@JvmStatic
fun main(args: Array<String>) {
val application = SpringApplication(MyApplication::class.java)
application.setBannerMode(Banner.Mode.OFF)
application.run(*args)
}
}
Или метода sources(…) класса SpringApplicationBuilder:
public class MyApplication {
public static void main(String[] args) {
new SpringApplicationBuilder()
.bannerMode(Banner.Mode.OFF)
.sources(MyApplication.class)
.run(args);
}
}
object MyApplication {
@JvmStatic
fun main(args: Array<String>) {
SpringApplicationBuilder()
.bannerMode(Banner.Mode.OFF)
.sources(MyApplication::class.java)
.run(*args)
}
}
Учитывая примеры выше, если у нас есть такая конфигурация:
spring.main.sources=com.example.MyDatabaseConfig,com.example.MyJmsConfig
spring.main.banner-mode=console spring:
main:
sources: "com.example.MyDatabaseConfig,com.example.MyJmsConfig"
banner-mode: "console" Фактическое приложение покажет баннер (как переопределённый конфигурацией) и использует три источника для ApplicationContext. Источники приложения:
-
MyApplication(из кода) -
MyDatabaseConfig(из внешней конфигурации) -
MyJmsConfig(из внешней конфигурации)
2.3. Изменение расположения внешних свойств приложения
По умолчанию свойства из разных источников добавляются в Spring Environment в определённом порядке (см. «features.html» в разделе «Функции Spring Boot» для точного порядка).
Вы также можете указать следующие системные свойства (или переменные окружения) для изменения поведения:
-
spring.config.name(SPRING_CONFIG_NAME): По умолчаниюapplicationв качестве корня имени файла. -
spring.config.location(SPRING_CONFIG_LOCATION): Файл для загрузки (например, ресурс из classpath или URL). Для этого документа настраивается отдельный источник свойствEnvironment, который можно переопределить системными свойствами, переменными окружения или командной строкой.
Независимо от того, что вы устанавливаете в среде, Spring Boot всегда загружает application.properties, как описано выше. По умолчанию, если используется YAML, файлы с расширениями ‘.yaml’ и ‘.yml’ также добавляются в список.
Если вы хотите получить подробную информацию о загружаемых файлах, вы можете установить уровень логирования org.springframework.boot.context.config на trace. |
2.4. Использование «коротких» аргументов командной строки
Некоторые предпочитают использовать (например) --port=9000 вместо --server.port=9000 для настройки свойств конфигурации в командной строке. Вы можете включить это поведение, используя плейсхолдеры в файле application.properties, как показано в следующем примере:
server.port=${port:8080} server:
port: "${port:8080}" Если вы наследуете от spring-boot-starter-parent POM, токен фильтра по умолчанию для maven-resources-plugins был изменён с ${*} на @ (то есть @maven.token@ вместо ${maven.token}) для предотвращения конфликтов с плейсхолдерами Spring. Если вы включили фильтрацию Maven для application.properties напрямую, возможно, вам также следует изменить токен фильтра по умолчанию, используя другие разделители. |
В данном случае привязка порта работает в среде PaaS, такой как Heroku или Cloud Foundry. На этих платформах переменная окружения PORT устанавливается автоматически, и Spring может привязаться к заглавным синонимам для свойств Environment. |
2.5. Использование YAML для внешних свойств
YAML является надмножеством JSON и, как таковой, представляет собой удобный синтаксис для хранения внешних свойств в иерархическом формате, как показано в следующем примере:
spring:
application:
name: "cruncher"
datasource:
driver-class-name: "com.mysql.jdbc.Driver"
url: "jdbc:mysql://localhost/test"
server:
port: 9000 Создайте файл с именем application.yaml и поместите его в корень вашего класса. Затем добавьте snakeyaml в свои зависимости (координаты Maven org.yaml:snakeyaml, уже включенные, если вы используете spring-boot-starter). Файл YAML парсится в Java-объект Map<String,Object> (как JSON-объект), а Spring Boot делает массив одноуровневым с ключами, разделёнными точками, как многие привыкли к файлам Properties в Java.
Предыдущий пример YAML соответствует следующему файлу application.properties:
spring.application.name=cruncher
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost/test
server.port=9000 См. «features.html» в разделе «Функции Spring Boot» для получения дополнительной информации о YAML.
2.6. Установка активных профилей Spring
Spring Environment имеет API для этого, но обычно вы устанавливаете системную переменную (spring.profiles.active) или переменную среды ОС (SPRING_PROFILES_ACTIVE). Также вы можете запустить своё приложение с аргументом -D (не забудьте разместить его перед именем главного класса или JAR-архивом), как показано ниже:
$ java -jar -Dspring.profiles.active=production demo-0.0.1-SNAPSHOT.jar В Spring Boot вы также можете установить активный профиль в application.properties, как показано в следующем примере:
spring.profiles.active=production spring:
profiles:
active: "production" Значение, установленное таким образом, заменяется системной переменной или переменной среды, но не методом SpringApplicationBuilder.profiles(). Таким образом, последний API Java может использоваться для дополнения профилей без изменения значений по умолчанию.
См. «features.html» в разделе «Функции Spring Boot» для получения дополнительной информации.
2.7. Установка имени профиля по умолчанию
Профиль по умолчанию — это профиль, который активируется, если никакой профиль не активен. По умолчанию имя профиля по умолчанию — default, но его можно изменить с помощью системной переменной (spring.profiles.default) или переменной среды ОС (SPRING_PROFILES_DEFAULT).
В Spring Boot вы также можете установить имя профиля по умолчанию в application.properties, как показано в следующем примере:
spring.profiles.default=dev spring:
profiles:
default: "dev" См. «features.html» в разделе «Функции Spring Boot» для получения дополнительной информации.
2.8. Изменение конфигурации в зависимости от среды
Spring Boot поддерживает файлы YAML и Properties с несколькими документами (подробнее см. features.html), которые могут быть активированы условно в зависимости от активных профилей.
Если документ содержит ключ spring.config.activate.on-profile, то значение профилей (список профилей или выражение профиля, разделённые запятыми) передаётся в метод Spring Environment.acceptsProfiles(). Если выражение профиля соответствует, то этот документ включается в итоговую слияние (в противном случае — нет), как показано в следующем примере:
server.port=9000
#---
spring.config.activate.on-profile=development
server.port=9001
#---
spring.config.activate.on-profile=production
server.port=0 server:
port: 9000
---
spring:
config:
activate:
on-profile: "development"
server:
port: 9001
---
spring:
config:
activate:
on-profile: "production"
server:
port: 0 В приведённом примере порт по умолчанию равен 9000. Однако, если активен профиль Spring под названием «development», порт равен 9001. Если активен профиль «production», порт равен 0.
| Документы сливаются в том порядке, в котором они встречаются. Более поздние значения переопределяют более ранние. |
2.9. Обнаружение встроенных параметров для внешних свойств
Spring Boot связывает внешние свойства из application.properties (или файлов YAML и других мест) с приложением во время выполнения. Не существует (и технически не может быть) исчерпывающего списка всех поддерживаемых свойств в одном месте, так как вклады могут поступать из дополнительных JAR-файлов в вашем классе.
Запущенное приложение с функциями Actuator имеет конечную точку configprops, которая отображает все связанные и связываемые свойства, доступные через @ConfigurationProperties.
В приложении есть пример application.properties со списком наиболее распространённых свойств, поддерживаемых Spring Boot. Окончательный список получается путем поиска в исходном коде аннотаций @ConfigurationProperties и @Value, а также при использовании Binder. Более подробную информацию о точном порядке загрузки свойств можно найти в «features.html».
3. Встроенные веб-серверы
Каждый веб-приложение Spring Boot включает встроенный веб-сервер. Эта функция порождает ряд вопросов по использованию, включая изменение встроенного сервера и его настройку. Этот раздел отвечает на эти вопросы.
3.1. Использование другого веб-сервера
Многие стартеры Spring Boot включают встроенные контейнеры по умолчанию.
-
Для приложений на основе servlet-стека,
spring-boot-starter-webвключает Tomcat, включаяspring-boot-starter-tomcat, но вы можете использоватьspring-boot-starter-jettyилиspring-boot-starter-undertowвместо этого. -
Для приложений на основе реактивного стека,
spring-boot-starter-webfluxвключает Reactor Netty, включаяspring-boot-starter-reactor-netty, но вы можете использоватьspring-boot-starter-tomcat,spring-boot-starter-jettyилиspring-boot-starter-undertowвместо этого.
При переключении на другой HTTP-сервер вам необходимо заменить зависимости по умолчанию на те, которые вам нужны. Для помощи в этом процессе Spring Boot предоставляет отдельный стартер для каждого поддерживаемого HTTP-сервера.
Следующий пример на Maven показывает, как исключить Tomcat и включить Jetty для Spring MVC:
<properties>
<servlet-api.version>3.1.0</servlet-api.version>
</properties>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- Exclude the Tomcat dependency -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use Jetty instead -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency> | Версия API servlet была переопределена, так как, в отличие от Tomcat 9 и Undertow 2, Jetty 9.4 не поддерживает servlet 4.0. |
Если вы хотите использовать Jetty 10, который поддерживает servlet 4.0, вы можете сделать это, как показано в следующем примере:
<properties>
<jetty.version>10.0.8</jetty.version>
</properties>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- Exclude the Tomcat dependency -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use Jetty instead -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<exclusions>
<!-- Exclude the Jetty-9 specific dependencies -->
<exclusion>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-server</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>javax-websocket-server-impl</artifactId>
</exclusion>
</exclusions>
</dependency> Обратите внимание, что вместе с исключением стартера Tomcat, необходимо также исключить несколько зависимостей, специфичных для Jetty9.
Следующий пример на Gradle настраивает необходимые зависимости и замену модулей, чтобы использовать Undertow вместо Reactor Netty для Spring WebFlux:
dependencies {
implementation "org.springframework.boot:spring-boot-starter-undertow"
implementation "org.springframework.boot:spring-boot-starter-webflux"
modules {
module("org.springframework.boot:spring-boot-starter-reactor-netty") {
replacedBy("org.springframework.boot:spring-boot-starter-undertow", "Use Undertow instead of Reactor Netty")
}
}
} spring-boot-starter-reactor-netty требуется для использования класса WebClient, поэтому вам может потребоваться сохранить зависимость от Netty даже тогда, когда вам нужно включить другой HTTP-сервер. |
3.2. Отключение веб-сервера
Если в вашем классе пути содержатся необходимые компоненты для запуска веб-сервера, Spring Boot автоматически запустит его. Для отключения этого поведения настройте WebApplicationType в вашем application.properties, как показано в следующем примере:
spring.main.web-application-type=none spring:
main:
web-application-type: "none" 3.3. Изменение порта HTTP
В автономном приложении основной порт HTTP по умолчанию равен 8080, но может быть задан с помощью server.port (например, в application.properties или в качестве системной переменной). Благодаря ослабленному привязыванию значений Environment, вы также можете использовать SERVER_PORT (например, как переменную среды ОС).
Чтобы полностью отключить HTTP-пункты доступа, но все равно создать WebApplicationContext, используйте server.port=-1 (иногда это полезно для тестирования).
Для получения более подробной информации см. «web.html» в разделе «Функции Spring Boot» или исходный код ServerProperties.
3.4. Использование случайного неназначенного порта HTTP
Чтобы искать свободный порт (используя системные средства ОС для предотвращения конфликтов), используйте server.port=0.
3.5. Обнаружение порта HTTP во время выполнения
Вы можете получить доступ к порту, на котором работает сервер, из логов или из WebServerApplicationContext через его WebServer. Лучший способ получить его и убедиться, что он был инициализирован, — добавить @Bean типа ApplicationListener<WebServerInitializedEvent> и извлечь контейнер из события при его публикации.
Тесты, которые используют @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT), также могут ввести фактический порт в поле с помощью аннотации @LocalServerPort, как показано в следующем примере:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyWebIntegrationTests {
@LocalServerPort
int port;
// ...
}
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyWebIntegrationTests {
@LocalServerPort
var port = 0
// ...
}
|
|
3.6. Включение сжатия ответов HTTP
Сжатие ответов HTTP поддерживается Jetty, Tomcat, Reactor Netty и Undertow. Его можно включить в application.properties, как показано ниже:
server.compression.enabled=true server:
compression:
enabled: true По умолчанию ответы должны быть длиной не менее 2048 байтов для выполнения сжатия. Вы можете настроить это поведение, задав свойство server.compression.min-response-size.
По умолчанию ответы сжимаются только в том случае, если их тип содержимого соответствует одному из следующих:
-
text/html -
text/xml -
text/plain -
text/css -
text/javascript -
application/javascript -
application/json -
application/xml
Вы можете настроить это поведение, задав свойство server.compression.mime-types.
3.7. Настройка SSL
SSL можно настроить декларативно, задав различные свойства server.ssl.*, обычно в application.properties или application.yaml. Следующий пример показывает настройку свойств SSL с помощью файла Java KeyStore:
server.port=8443
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=secret
server.ssl.key-password=another-secret server:
port: 8443
ssl:
key-store: "classpath:keystore.jks"
key-store-password: "secret"
key-password: "another-secret" Следующий пример демонстрирует настройку свойств SSL с использованием файлов сертификата и закрытого ключа в формате PEM:
server.port=8443
server.ssl.certificate=classpath:my-cert.crt
server.ssl.certificate-private-key=classpath:my-cert.key
server.ssl.trust-certificate=classpath:ca-cert.crt server:
port: 8443
ssl:
certificate: "classpath:my-cert.crt"
certificate-private-key: "classpath:my-cert.key"
trust-certificate: "classpath:ca-cert.crt" Альтернативно, материалы доверия SSL можно настроить в пакете SSL и применить к веб-серверу, как показано в этом примере:
server.port=8443
server.ssl.bundle=example server:
port: 8443
ssl:
bundle: "example" См. Ssl для получения подробной информации обо всех поддерживаемых свойствах.
Использование такой конфигурации, как в предыдущем примере, означает, что приложение больше не поддерживает обычный HTTP-соединитель на порту 8080. Spring Boot не поддерживает настройку как HTTP-соединителя, так и HTTPS-соединителя через application.properties. Если вам нужно иметь оба, вам необходимо настроить один из них программно. Мы рекомендуем использовать application.properties для настройки HTTPS, поскольку HTTP-соединитель проще настроить программно.
3.8. Настройка HTTP/2
Вы можете включить поддержку HTTP/2 в своем приложении Spring Boot с помощью свойства конфигурации server.http2.enabled. Поддерживаются как h2 (HTTP/2 через TLS), так и h2c (HTTP/2 через TCP). Для использования h2, также необходимо включить SSL. Когда SSL не включен, будет использоваться h2c. Например, вы можете использовать h2c, когда ваше приложение работает за прокси-сервером, который выполняет завершение TLS.
3.8.1. HTTP/2 с Tomcat
Spring Boot по умолчанию поставляется с Tomcat 10.1.x, который поддерживает h2c и h2 без дополнительных настроек. В качестве альтернативы, вы можете использовать libtcnative для поддержки h2, если библиотека и её зависимости установлены на операционной системе хоста.
Если каталог библиотеки не доступен в пути к библиотекам JVM, его нужно сделать доступным. Это можно сделать с помощью аргумента JVM, такого как -Djava.library.path=/usr/local/opt/tomcat-native/lib. Более подробная информация в официальной документации Tomcat.
3.8.2. HTTP/2 с Jetty
Для поддержки HTTP/2 Jetty требует дополнительной зависимости org.eclipse.jetty.http2:http2-server. Для использования h2c другие зависимости не требуются. Чтобы использовать h2, вам также необходимо выбрать одну из следующих зависимостей в зависимости от вашей среды развертывания:
-
org.eclipse.jetty:jetty-alpn-java-serverдля использования встроенной поддержки JDK -
org.eclipse.jetty:jetty-alpn-conscrypt-serverи библиотеку Conscrypt
3.8.3. HTTP/2 с Reactor Netty
По умолчанию spring-boot-webflux-starter использует Reactor Netty в качестве сервера. Reactor Netty поддерживает h2c и h2 без дополнительных настроек. Для оптимальной производительности сервер также поддерживает h2 с нативными библиотеками. Для этого ваше приложение должно иметь дополнительную зависимость.
Spring Boot управляет версией io.netty:netty-tcnative-boringssl-static «uber jar», содержащей нативные библиотеки для всех платформ. Разработчики могут выбрать импорт только необходимых зависимостей с помощью классификатора (см. официальную документацию Netty).
3.8.4. HTTP/2 с Undertow
Undertow поддерживает h2c и h2 по умолчанию.
3.9. Настройка веб-сервера
В целом, вы должны сначала рассмотреть использование одного из многих доступных ключей конфигурации и настроить свой веб-сервер, добавив новые записи в файл application.properties или application.yaml. См. «Поиск встроенных параметров для внешних свойств». Пространство имен server.* здесь довольно полезно, и оно включает подпространства, такие как server.tomcat.*, server.jetty.* и другие, для функций, специфичных для сервера. См. список application-properties.html.
Предыдущие разделы уже охватывали многие распространённые случаи использования, такие как сжатие, SSL или HTTP/2. Однако, если для вашего случая использования не существует ключа конфигурации, следует обратиться к WebServerFactoryCustomizer. Вы можете объявить такой компонент и получить доступ к фабрике сервера, соответствующей вашему выбору: вы должны выбрать вариант для выбранного сервера (Tomcat, Jetty, Reactor Netty, Undertow) и выбранной веб-стек (servlet или реактивный).
Следующий пример предназначен для Tomcat со стеком spring-boot-starter-web (servlet):
@Component
public class MyTomcatWebServerCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
// customize the factory here
}
}
@Component
class MyTomcatWebServerCustomizer : WebServerFactoryCustomizer<TomcatServletWebServerFactory?> {
override fun customize(factory: TomcatServletWebServerFactory?) {
// customize the factory here
}
}
Spring Boot использует эту инфраструктуру внутри для автоматической настройки сервера. Автоконфигурированные WebServerFactoryCustomizer бины имеют порядок 0 и будут обработаны перед любыми пользовательскими кастомайзерами, если только не указан явный порядок. |
После получения доступа к WebServerFactory с помощью кастомайзера, вы можете использовать его для настройки отдельных частей, таких как коннекторы, ресурсы сервера или сам сервер — все с использованием API, специфичных для сервера.
В дополнение Spring Boot предоставляет:
| Сервер | Servlet-стек | Реактивный стек |
|---|---|---|
Tomcat |
|
|
Jetty |
|
|
Undertow |
|
|
Reactor | N/A |
|
В крайнем случае, вы также можете объявить свой собственный WebServerFactory бин, который переопределит бин, предоставленный Spring Boot. Когда вы это сделаете, автоконфигурированные кастомайзеры всё равно применяются к вашей пользовательской фабрике, поэтому используйте этот вариант с осторожностью.
3.10. Добавление сервлета, фильтра или слушателя в приложение
В приложении с servlet-стеком, то есть с spring-boot-starter-web, есть два способа добавить Servlet, Filter, ServletContextListener и других слушателей, поддерживаемых Servlet API, в ваше приложение:
3.10.1. Добавление сервлета, фильтра или слушателя с помощью Spring Bean
Чтобы добавить Servlet, Filter или сервлет *Listener с помощью Spring Bean, вы должны предоставить определение @Bean для него. Это может быть полезно, когда вам нужно ввести конфигурацию или зависимости. Однако, будьте очень внимательны, чтобы они не вызывали немедленную инициализацию слишком большого количества других бинов, так как они должны быть установлены в контейнере очень рано на жизненном цикле приложения. (Например, не стоит зависеть от вашей DataSource или конфигурации JPA.) Вы можете обойти такие ограничения, инициируя бины лениво, при первом использовании, а не при инициализации.
В случае фильтров и сервлетов вы также можете добавить отображения и параметры инициализации, добавив FilterRegistrationBean или ServletRegistrationBean вместо или дополнительно к базовому компоненту.
| Если для регистрации фильтра не указан |
Как и любой другой Spring-бин, вы можете определить порядок бинов фильтров сервлетов; пожалуйста, убедитесь, что проверили раздел «web.html».
Отключение регистрации сервлета или фильтра
Как уже описано, все Servlet или Filter бины автоматически регистрируются в контейнере сервлетов. Чтобы отключить регистрацию определенного Filter или Servlet бина, создайте бин регистрации для него и отметьте его как отключенный, как показано в следующем примере:
@Configuration(proxyBeanMethods = false)
public class MyFilterConfiguration {
@Bean
public FilterRegistrationBean<MyFilter> registration(MyFilter filter) {
FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>(filter);
registration.setEnabled(false);
return registration;
}
}
@Configuration(proxyBeanMethods = false)
class MyFilterConfiguration {
@Bean
fun registration(filter: MyFilter): FilterRegistrationBean<MyFilter> {
val registration = FilterRegistrationBean(filter)
registration.isEnabled = false
return registration
}
}
3.10.2. Добавление сервлетов, фильтров и слушателей с помощью сканирования по классовой дорожке
Классы, аннотированные @WebServlet, @WebFilter и @WebListener, могут быть автоматически зарегистрированы в встроенном контейнере сервлетов, если аннотировать класс @Configuration с помощью @ServletComponentScan и указать пакет(ы), содержащие компоненты, которые вы хотите зарегистрировать. По умолчанию, @ServletComponentScan сканирует пакет класса с аннотацией.
3.11. Настройка ведения журнала доступа
Журналы доступа можно настроить для Tomcat, Undertow и Jetty через соответствующие пространства имён.
Например, следующие настройки ведут журнал доступа в Tomcat с пользовательским шаблоном.
server.tomcat.basedir=my-tomcat
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%t %a %r %s (%D ms) server:
tomcat:
basedir: "my-tomcat"
accesslog:
enabled: true
pattern: "%t %a %r %s (%D ms)" По умолчанию журналы находятся в каталоге logs относительно базового каталога Tomcat. По умолчанию каталог logs является временным, поэтому возможно нужно будет изменить базовый каталог Tomcat или использовать абсолютный путь к журналам. В приведённом примере журналы доступны в my-tomcat/logs относительно рабочей директории приложения. |
Журнал доступа для Undertow можно настроить аналогичным образом, как показано в следующем примере:
server.undertow.accesslog.enabled=true
server.undertow.accesslog.pattern=%t %a %r %s (%D ms)
server.undertow.options.server.record-request-start-time=true server:
undertow:
accesslog:
enabled: true
pattern: "%t %a %r %s (%D ms)"
options:
server:
record-request-start-time: true Обратите внимание, что помимо включения ведения журнала доступа и настройки его шаблона, также включено регистрирование времени начала запросов. Это необходимо при включении времени ответа (%D) в шаблон журнала доступа. Журналы хранятся в каталоге logs относительно рабочей директории приложения. Вы можете настроить это расположение, установив свойство server.undertow.accesslog.dir.
Наконец, ведение журнала доступа для Jetty также можно настроить следующим образом:
server.jetty.accesslog.enabled=true
server.jetty.accesslog.filename=/var/log/jetty-access.log server:
jetty:
accesslog:
enabled: true
filename: "/var/log/jetty-access.log" По умолчанию журналы перенаправляются в System.err. Более подробную информацию см. в документации Jetty.
3.12. Работа за прокси-сервером
Если ваше приложение работает за прокси, балансировщиком нагрузки или в облаке, информация о запросе (например, хост, порт, схема…) может измениться по пути. Ваше приложение может работать на 10.10.10.10:8080, но клиенты HTTP должны видеть только example.org.
RFC7239 «Forwarded Headers» определяет заголовок HTTP Forwarded; прокси-серверы могут использовать этот заголовок для предоставления информации об исходном запросе. Вы можете настроить своё приложение для чтения этих заголовков и автоматического использования этой информации при создании ссылок и отправке их клиентам в ответах HTTP 302, JSON документах или HTML страницах. Существуют также нестандартные заголовки, такие как X-Forwarded-Host, X-Forwarded-Port, X-Forwarded-Proto, X-Forwarded-Ssl и X-Forwarded-Prefix.
Если прокси добавляет обычно используемые заголовки X-Forwarded-For и X-Forwarded-Proto, достаточно установить server.forward-headers-strategy на значение NATIVE для поддержки этих заголовков. В этом случае веб-серверы сами поддерживают эту функцию; вы можете проверить их конкретную документацию, чтобы узнать о специфическом поведении.
Если этого недостаточно, Spring Framework предоставляет ForwardedHeaderFilter. Вы можете зарегистрировать его как фильтр сервлета в своём приложении, установив server.forward-headers-strategy на значение FRAMEWORK.
Если вы используете Tomcat и завершаете SSL на прокси, server.tomcat.redirect-context-root должно быть установлено на false. Это позволяет заголовку X-Forwarded-Proto учитывать до выполнения любых перенаправлений. |
Если ваше приложение выполняется в Cloud Foundry, Heroku или Kubernetes, свойство server.forward-headers-strategy по умолчанию устанавливается в NATIVE. Во всех остальных случаях оно по умолчанию устанавливается в NONE. |
3.12.1. Настройка прокси-конфигурации Tomcat
Если вы используете Tomcat, вы можете дополнительно настроить имена заголовков, используемых для передачи информации о «перенаправлении», как показано в следующем примере:
server.tomcat.remoteip.remote-ip-header=x-your-remote-ip-header
server.tomcat.remoteip.protocol-header=x-your-protocol-header server:
tomcat:
remoteip:
remote-ip-header: "x-your-remote-ip-header"
protocol-header: "x-your-protocol-header" Tomcat также настроен с регулярным выражением, которое сопоставляет внутренние прокси-серверы, которым необходимо доверять. См. server.tomcat.remoteip.internal-proxies запись в приложении для её значения по умолчанию. Вы можете настроить конфигурацию клапана, добавив запись в application.properties, как показано в следующем примере:
server.tomcat.remoteip.internal-proxies=192\\.168\\.\\d{1,3}\\.\\d{1,3} server:
tomcat:
remoteip:
internal-proxies: "192\\.168\\.\\d{1,3}\\.\\d{1,3}" Вы можете доверять всем прокси, установив internal-proxies в пустое значение (но не делайте этого в производстве). |
Вы можете полностью контролировать конфигурацию RemoteIpValve Tomcat, отключив автоматическое управление (для этого установите server.forward-headers-strategy=NONE) и добавив новый экземпляр клапана, используя bean WebServerFactoryCustomizer.
3.13. Включение нескольких коннекторов в Tomcat
Вы можете добавить org.apache.catalina.connector.Connector в TomcatServletWebServerFactory, что позволит иметь несколько коннекторов, включая HTTP и HTTPS коннекторы, как показано в следующем примере:
@Configuration(proxyBeanMethods = false)
public class MyTomcatConfiguration {
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> connectorCustomizer() {
return (tomcat) -> tomcat.addAdditionalTomcatConnectors(createConnector());
}
private Connector createConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setPort(8081);
return connector;
}
}
@Configuration(proxyBeanMethods = false)
class MyTomcatConfiguration {
@Bean
fun connectorCustomizer(): WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
return WebServerFactoryCustomizer { tomcat: TomcatServletWebServerFactory ->
tomcat.addAdditionalTomcatConnectors(
createConnector()
)
}
}
private fun createConnector(): Connector {
val connector = Connector("org.apache.coyote.http11.Http11NioProtocol")
connector.port = 8081
return connector
}
}
3.14. Включение реестра MBean Tomcat
Реестр MBean встроенного Tomcat по умолчанию отключен. Это минимизирует использование памяти Tomcat. Если вы хотите использовать MBeans Tomcat, например, для того, чтобы Micrometer мог использовать их для экспонирования метрик, вы должны использовать свойство server.tomcat.mbeanregistry.enabled, как показано в следующем примере:
server.tomcat.mbeanregistry.enabled=true server:
tomcat:
mbeanregistry:
enabled: true 3.15. Включение нескольких слушателей в Undertow
Добавьте UndertowBuilderCustomizer в UndertowServletWebServerFactory и добавьте слушателя в Builder, как показано в следующем примере:
@Configuration(proxyBeanMethods = false)
public class MyUndertowConfiguration {
@Bean
public WebServerFactoryCustomizer<UndertowServletWebServerFactory> undertowListenerCustomizer() {
return (factory) -> factory.addBuilderCustomizers(this::addHttpListener);
}
private Builder addHttpListener(Builder builder) {
return builder.addHttpListener(8080, "0.0.0.0");
}
}
@Configuration(proxyBeanMethods = false)
class MyUndertowConfiguration {
@Bean
fun undertowListenerCustomizer(): WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
return WebServerFactoryCustomizer { factory: UndertowServletWebServerFactory ->
factory.addBuilderCustomizers(
UndertowBuilderCustomizer { builder: Undertow.Builder -> addHttpListener(builder) })
}
}
private fun addHttpListener(builder: Undertow.Builder): Undertow.Builder {
return builder.addHttpListener(8080, "0.0.0.0")
}
}
3.16. Создание конечных точек WebSocket с помощью @ServerEndpoint
Если вы хотите использовать @ServerEndpoint в приложении Spring Boot, которое использует встроенный контейнер, вы должны объявить единственный ServerEndpointExporter @Bean, как показано в следующем примере:
@Configuration(proxyBeanMethods = false)
public class MyWebSocketConfiguration {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
@Configuration(proxyBeanMethods = false)
class MyWebSocketConfiguration {
@Bean
fun serverEndpointExporter(): ServerEndpointExporter {
return ServerEndpointExporter()
}
}
Bean, показанный в предыдущем примере, регистрирует все @ServerEndpoint аннотированные бины в базовом контейнере WebSocket. При развертывании в автономном контейнере сервлетов эта роль выполняется инициализатором сервлета контейнера, и bean ServerEndpointExporter не требуется.
4. Spring MVC
Spring Boot имеет ряд стартеров, которые включают Spring MVC. Обратите внимание, что некоторые стартеры включают зависимость от Spring MVC, а не включают его напрямую. В этом разделе отвечаются на часто задаваемые вопросы о Spring MVC и Spring Boot.
4.1. Написание JSON REST-сервиса
Любой Spring @RestController в приложении Spring Boot должен отображать JSON-ответ по умолчанию, если Jackson2 находится в пути к классам, как показано в следующем примере:
@RestController
public class MyController {
@RequestMapping("/thing")
public MyThing thing() {
return new MyThing();
}
}
@RestController
class MyController {
@RequestMapping("/thing")
fun thing(): MyThing {
return MyThing()
}
}
До тех пор, пока MyThing может быть сериализован Jackson2 (это верно для обычного POJO или объекта Groovy), тогда localhost:8080/thing по умолчанию отображает JSON-представление этого объекта. Обратите внимание, что в браузере иногда можно увидеть XML-ответы, потому что браузеры, как правило, отправляют заголовки accept, которые отдают предпочтение XML.
4.2. Написание XML REST-сервиса
Если у вас есть расширение Jackson XML (jackson-dataformat-xml) в пути к классам, вы можете использовать его для отображения XML-ответов. Предыдущий пример, который мы использовали для JSON, будет работать. Чтобы использовать рендерер Jackson XML, добавьте следующую зависимость в свой проект:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency> Если расширение XML Jackson недоступно, а JAXB доступно, XML можно отобразить с дополнительным требованием наличия MyThing, аннотированной как @XmlRootElement, как показано в следующем примере:
@XmlRootElement
public class MyThing {
private String name;
}
@XmlRootElement
class MyThing {
var name: String? = null
}
Вам нужно убедиться, что библиотека JAXB является частью вашего проекта, например, добавив:
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</dependency> Чтобы заставить сервер отобразить XML вместо JSON, вам, возможно, придется отправить заголовок Accept: text/xml (или использовать браузер). |
4.3. Настройка Jackson ObjectMapper
Spring MVC (клиентская и серверная стороны) использует HttpMessageConverters для согласования преобразования содержимого в HTTP-обмене. Если Jackson находится в пути к классам, вы уже получаете преобразователь(и) по умолчанию, предоставляемые Jackson2ObjectMapperBuilder, экземпляр которого настроен для вас автоматически.
Экземпляр ObjectMapper (или XmlMapper для преобразователя Jackson XML) (созданный по умолчанию) имеет следующие настроенные свойства:
-
MapperFeature.DEFAULT_VIEW_INCLUSIONотключен -
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIESотключен -
SerializationFeature.WRITE_DATES_AS_TIMESTAMPSотключен
Spring Boot также имеет некоторые функции, которые облегчают настройку этого поведения.
Вы можете настроить экземпляры ObjectMapper и XmlMapper, используя среду. Jackson предоставляет обширную suite функций включения/выключения, которые можно использовать для настройки различных аспектов обработки. Эти функции описаны в шести перечислениях (в Jackson), которые сопоставляются со свойствами в среде:
| Перечисление | Свойство | Значения |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Например, чтобы включить красивую печать, установите spring.jackson.serialization.indent_output=true. Обратите внимание, что благодаря использованию расслабленной привязки, регистр indent_output не обязательно должен совпадать с регистром соответствующего константы перечисления, который есть INDENT_OUTPUT.
Эта настройка на основе среды применяется к автоматически настроенному бину Jackson2ObjectMapperBuilder и применяется к любым мапперам, созданным с использованием конструктора, включая автоматически настроенный ObjectMapper.
Контекст’s Jackson2ObjectMapperBuilder можно настроить с помощью одного или нескольких Jackson2ObjectMapperBuilderCustomizer бинов. Такие пользовательские бины-настройщики могут быть отсортированы (собственный настройщик Boot имеет порядок 0), что позволяет применять дополнительную настройку как до, так и после настройки Boot.
Любые бины типа com.fasterxml.jackson.databind.Module автоматически регистрируются с автоматически настроенным Jackson2ObjectMapperBuilder и применяются ко всем экземплярам ObjectMapper, которые он создает. Это обеспечивает глобальный механизм для внесения пользовательских модулей при добавлении новых функций в ваше приложение.
Если вы хотите полностью заменить стандартный ObjectMapper, либо определите @Bean этого типа и отметьте его как @Primary, или, если вы предпочитаете подход на основе конструктора, определите Jackson2ObjectMapperBuilder @Bean. Обратите внимание, что в любом случае это отключит всю автоматическую настройку ObjectMapper.
Если вы предоставите любые @Beans типа MappingJackson2HttpMessageConverter, они заменят значение по умолчанию в настройке MVC. Также предоставлен удобный бин типа HttpMessageConverters (он всегда доступен, если вы используете стандартную конфигурацию MVC). Он имеет несколько полезных методов для доступа к стандартным и пользовательским улучшенным преобразователям сообщений.
См. раздел «Настройка отображения @ResponseBody» и исходный код WebMvcAutoConfiguration для получения более подробной информации.
4.4. Настройка отображения @ResponseBody
Spring использует HttpMessageConverters для отображения @ResponseBody (или ответов от @RestController). Вы можете внести дополнительные преобразователи, добавив бины соответствующего типа в контекст Spring Boot. Если добавленный вами бин имеет тип, который должен был быть включён по умолчанию (например, MappingJackson2HttpMessageConverter для преобразований JSON), он заменит значение по умолчанию. Предоставлен удобный бин типа HttpMessageConverters, который всегда доступен, если вы используете стандартную конфигурацию MVC. Он имеет несколько полезных методов для доступа к стандартным и пользовательским улучшенным преобразователям сообщений (например, это может быть полезно, если вы хотите вручную ввести их в пользовательский RestTemplate).
Как и в обычном использовании MVC, любые WebMvcConfigurer бины, которые вы предоставите, также могут внести преобразователи, перезаписав метод configureMessageConverters. Однако, в отличие от обычного MVC, вы можете предоставить только дополнительные преобразователи, которые вам нужны (потому что Spring Boot использует тот же механизм для предоставления своих значений по умолчанию). Наконец, если вы откажетесь от стандартной конфигурации Spring Boot MVC, предоставив свою собственную конфигурацию @EnableWebMvc, вы можете полностью взять под контроль и сделать всё вручную, используя getMessageConverters из WebMvcConfigurationSupport.
См. исходный код WebMvcAutoConfiguration для получения более подробной информации.
4.5. Обработка загрузок файлов с множественной частью
Spring Boot использует API сервлета 5 jakarta.servlet.http.Part для поддержки загрузки файлов. По умолчанию Spring Boot настраивает Spring MVC с максимальным размером 1 МБ на файл и максимальным размером данных файлов в 10 МБ в одном запросе. Вы можете переопределить эти значения, местоположение, в котором хранятся промежуточные данные (например, в каталог /tmp), и порог, после которого данные выгружаются на диск, используя свойства, доступные в классе MultipartProperties. Например, если вы хотите указать, что файлы должны быть без ограничений, установите свойство spring.servlet.multipart.max-file-size в значение -1.
Поддержка множественной части полезна, когда вы хотите получить данные файла с кодировкой множественной части в качестве параметра, аннотированного @RequestParam, типа MultipartFile, в методе обработчика контроллера Spring MVC.
См. исходный код MultipartAutoConfiguration для получения более подробной информации.
| Рекомендуется использовать встроенную поддержку контейнера для загрузки файлов с множественной частью, а не добавлять дополнительную зависимость, такую как Apache Commons File Upload. |
4.6. Отключение DispatcherServlet Spring MVC
По умолчанию все содержимое отображается с корня вашего приложения (/). Если вы хотите сопоставить с другим путем, вы можете настроить его следующим образом:
spring.mvc.servlet.path=/mypath spring:
mvc:
servlet:
path: "/mypath" Если у вас есть дополнительные сервлеты, вы можете объявить @Bean типа Servlet или ServletRegistrationBean для каждого, и Spring Boot прозрачно зарегистрирует их в контейнере. Поскольку сервлеты регистрируются таким образом, они могут быть сопоставлены с подконтекстом DispatcherServlet без вызова его.
Настройка DispatcherServlet самостоятельно — необычно, но если вам действительно нужно это сделать, необходимо также предоставить @Bean типа DispatcherServletPath для указания пути к вашему пользовательскому DispatcherServlet.
4.7. Отключение стандартной конфигурации MVC
Самый простой способ полностью контролировать конфигурацию MVC — предоставить собственную @Configuration с аннотацией @EnableWebMvc. Это позволит вам полностью контролировать конфигурацию MVC.
4.8. Настройка ViewResolvers
ViewResolver — это ключевой компонент Spring MVC, переводящий имена представлений в @Controller в фактические реализации View. Обратите внимание, что ViewResolvers в основном используются в приложениях с пользовательским интерфейсом, а не в сервисах в стиле REST (View не используется для рендеринга @ResponseBody). Существует множество реализаций ViewResolver на выбор, и Spring не навязывает предпочтений. Spring Boot, в свою очередь, устанавливает одну или две по умолчанию, в зависимости от того, что найдено в классе и в контексте приложения. DispatcherServlet использует все найденные в приложении разрешители, пробуя каждый по очереди до получения результата. Если вы добавите собственный разрешитель, вам нужно учитывать порядок его добавления.
WebMvcAutoConfiguration добавляет следующие ViewResolvers в ваш контекст:
-
InternalResourceViewResolverс именем ‘defaultViewResolver’. Этот разрешитель находит физические ресурсы, которые могут быть отображены с использованиемDefaultServlet(включая статические ресурсы и страницы JSP, если вы их используете). Он применяет префикс и суффикс к имени представления и затем ищет физический ресурс с этим путем в контексте сервлета (значения по умолчанию пустые, но доступны для внешней конфигурации черезspring.mvc.view.prefixиspring.mvc.view.suffix). Вы можете переопределить его, предоставив бины того же типа. -
BeanNameViewResolverс именем ‘beanNameViewResolver’. Это полезный член цепочки разрешителей представлений, выбирающий любые бины с тем же именем, что и разрешаемоеView. Не должно потребоваться переопределение или замена этого разрешителя. -
ContentNegotiatingViewResolverс именем ‘viewResolver’ добавляется только в том случае, если фактически присутствуют бины типаView. Это составной разрешитель, делегирующий всем остальным и пытающийся найти соответствие переданному клиентом HTTP-заголовку «Accept». Существует полезная статья оContentNegotiatingViewResolver, которую вы можете изучить для получения дополнительной информации, а также исходный код для подробного изучения. Вы можете отключить автоматически настроенныйContentNegotiatingViewResolver, определив бины с именем ‘viewResolver’. -
Если вы используете Thymeleaf, у вас также есть
ThymeleafViewResolverс именем ‘thymeleafViewResolver’. Он ищет ресурсы, окружая имя представления префиксом и суффиксом. Префикс —spring.thymeleaf.prefix, а суффикс —spring.thymeleaf.suffix. Значения префикса и суффикса по умолчанию равны ‘classpath:/templates/’ и ‘.html’ соответственно. Вы можете переопределитьThymeleafViewResolver, предоставив бины с таким же именем. -
Если вы используете FreeMarker, у вас также есть
FreeMarkerViewResolverс именем ‘freeMarkerViewResolver’. Он ищет ресурсы в пути загрузчика (который внешне указан вspring.freemarker.templateLoaderPathи имеет значение по умолчанию ‘classpath:/templates/’), окружая имя представления префиксом и суффиксом. Префикс внешне задан вspring.freemarker.prefix, а суффикс — вspring.freemarker.suffix. Значения префикса и суффикса по умолчанию пустые и ‘.ftlh’ соответственно. Вы можете переопределитьFreeMarkerViewResolver, предоставив бины с таким же именем. -
Если вы используете шаблоны Groovy (на самом деле, если
groovy-templatesнаходится в вашем классе), у вас также естьGroovyMarkupViewResolverс именем ‘groovyMarkupViewResolver’. Он ищет ресурсы в пути загрузчика, окружая имя представления префиксом и суффиксом (внешне указанными вspring.groovy.template.prefixиspring.groovy.template.suffix). Префикс и суффикс имеют значения по умолчанию ‘classpath:/templates/’ и ‘.tpl’ соответственно. Вы можете переопределитьGroovyMarkupViewResolver, предоставив бины с таким же именем. -
Если вы используете Mustache, у вас также есть
MustacheViewResolverс именем ‘mustacheViewResolver’. Он ищет ресурсы, окружая имя представления префиксом и суффиксом. Префикс —spring.mustache.prefix, а суффикс —spring.mustache.suffix. Значения префикса и суффикса по умолчанию равны ‘classpath:/templates/’ и ‘.mustache’ соответственно. Вы можете переопределитьMustacheViewResolver, предоставив бины с таким же именем.
Для получения дополнительной информации ознакомьтесь со следующими разделами:
5. Jersey
5.1. Защита конечных точек Jersey с помощью Spring Security
Spring Security может использоваться для защиты веб-приложения, основанного на Jersey, аналогично тому, как это делается для веб-приложения на основе Spring MVC. Однако, если вы хотите использовать уровень безопасности Spring Security на уровне методов с Jersey, вам необходимо настроить Jersey на использование setStatus(int), а не sendError(int). Это предотвращает Jersey от завершения ответа до того, как Spring Security получит возможность сообщить клиенту об ошибках аутентификации или авторизации.
Свойство jersey.config.server.response.setStatusOverSendError должно быть установлено в значение true в бине приложения ResourceConfig, как показано в следующем примере:
@Component
public class JerseySetStatusOverSendErrorConfig extends ResourceConfig {
public JerseySetStatusOverSendErrorConfig() {
register(Endpoint.class);
setProperties(Collections.singletonMap("jersey.config.server.response.setStatusOverSendError", true));
}
}
5.2. Использование Jersey вместе с другой веб-фреймворком
Чтобы использовать Jersey вместе с другим веб-фреймворком, таким как Spring MVC, его следует настроить таким образом, чтобы он позволял другому фреймворку обрабатывать запросы, которые он не может обработать. Во-первых, настройте Jersey на использование фильтра, а не сервлета, настроив свойство приложения spring.jersey.type со значением filter. Во-вторых, настройте ваш ResourceConfig на перенаправление запросов, которые привели бы к ошибке 404, как показано в следующем примере.
@Component
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(Endpoint.class);
property(ServletProperties.FILTER_FORWARD_ON_404, true);
}
}
6. Клиенты HTTP
Spring Boot предлагает ряд стартеров, работающих с клиентами HTTP. В этом разделе рассматриваются вопросы, связанные с их использованием.
6.1. Настройка RestTemplate для использования прокси
Как описано в io.html, вы можете использовать RestTemplateCustomizer с RestTemplateBuilder для построения настроенного RestTemplate. Это рекомендуемый подход для создания RestTemplate, настроенного для использования прокси.
Точные детали настройки прокси зависят от используемого базового фабрики запросов клиента.
6.2. Настройка TcpClient, используемого WebClient на основе Reactor Netty
Когда Reactor Netty присутствует в classpath, настраивается WebClient на основе Reactor Netty. Для настройки обработки сетевых соединений клиентом, укажите бин ClientHttpConnector. Следующий пример настраивает таймаут подключения в 60 секунд и добавляет ReadTimeoutHandler:
@Configuration(proxyBeanMethods = false)
public class MyReactorNettyClientConfiguration {
@Bean
ClientHttpConnector clientHttpConnector(ReactorResourceFactory resourceFactory) {
HttpClient httpClient = HttpClient.create(resourceFactory.getConnectionProvider())
.runOn(resourceFactory.getLoopResources())
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 60000)
.doOnConnected((connection) -> connection.addHandlerLast(new ReadTimeoutHandler(60)));
return new ReactorClientHttpConnector(httpClient);
}
}
@Configuration(proxyBeanMethods = false)
class MyReactorNettyClientConfiguration {
@Bean
fun clientHttpConnector(resourceFactory: ReactorResourceFactory): ClientHttpConnector {
val httpClient = HttpClient.create(resourceFactory.connectionProvider)
.runOn(resourceFactory.loopResources)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 60000)
.doOnConnected { connection ->
connection.addHandlerLast(ReadTimeoutHandler(60))
}
return ReactorClientHttpConnector(httpClient)
}
}
Обратите внимание на использование ReactorResourceFactory для поставщика подключений и ресурсов цикла событий. Это обеспечивает эффективное совместное использование ресурсов для сервера, принимающего запросы, и клиента, отправляющего запросы. |
7. Ведение журнала
В Spring Boot нет обязательной зависимости для ведения журнала, за исключением API Commons Logging, который обычно предоставляется модулем spring-jcl Spring Framework. Для использования Logback необходимо включить его и spring-jcl в пути к классам. Рекомендуемый способ сделать это — через стартеры, которые все зависят от spring-boot-starter-logging. Для веб-приложения вам нужен только spring-boot-starter-web, так как он транзитивно зависит от стартера ведения журнала. Если вы используете Maven, следующая зависимость добавит для вас ведение журнала:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> Spring Boot имеет абстракцию LoggingSystem, которая пытается настроить ведение журнала на основе содержимого пути к классам. Если Logback доступен, он используется в первую очередь.
Если единственное изменение, которое вам нужно внести в ведение журнала, — это установить уровни различных логгеров, вы можете сделать это в application.properties, используя префикс «logging.level», как показано в следующем примере:
logging.level.org.springframework.web=debug
logging.level.org.hibernate=error logging:
level:
org.springframework.web: "debug"
org.hibernate: "error" Вы также можете установить расположение файла, в который будет записываться журнал (в дополнение к консоли), используя logging.file.name.
Для настройки более подробных параметров системы ведения журнала необходимо использовать собственный формат конфигурации, поддерживаемый LoggingSystem. По умолчанию Spring Boot подбирает собственную конфигурацию из своего расположения по умолчанию для системы (например, classpath:logback.xml для Logback), но вы можете установить расположение файла конфигурации, используя свойство logging.config.
7.1. Настройка Logback для ведения журнала
Если вам необходимо внести настройки в Logback, выходящие за рамки тех, которые можно достичь с помощью application.properties, вам необходимо добавить стандартный файл конфигурации logback. Вы можете добавить файл logback.xml в корень вашего пути к классам, чтобы Logback его нашел. Вы также можете использовать logback-spring.xml, если хотите использовать расширения Spring Boot Logback.
| Документация Logback содержит специальный раздел, подробно описывающий конфигурацию. |
Spring Boot предоставляет ряд конфигураций Logback, которые могут быть included в вашей собственной конфигурации. Эти конфигурации предназначены для повторного применения некоторых общих соглашений Spring Boot.
Следующие файлы предоставляются в org/springframework/boot/logging/logback/:
-
defaults.xml— предоставляет правила преобразования, свойства шаблонов и общие конфигурации логгеров. -
console-appender.xml— добавляетConsoleAppender, используяCONSOLE_LOG_PATTERN. -
file-appender.xml— добавляетRollingFileAppender, используяFILE_LOG_PATTERNиROLLING_FILE_NAME_PATTERNс соответствующими настройками.
Кроме того, предоставляется устаревший файл base.xml для совместимости со старыми версиями Spring Boot.
Типичный настраиваемый файл logback.xml будет выглядеть примерно так:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
<logger name="org.springframework.web" level="DEBUG"/>
</configuration> Ваш файл конфигурации logback также может использовать системные свойства, которые LoggingSystem создает для вас:
-
${PID}: Текущий идентификатор процесса. -
${LOG_FILE}: Был ли установленlogging.file.nameво внешней конфигурации Boot. -
${LOG_PATH}: Был ли установленlogging.file.path(представляющий каталог для хранения файлов логов) во внешней конфигурации Boot. -
${LOG_EXCEPTION_CONVERSION_WORD}: Был ли установленlogging.exception-conversion-wordво внешней конфигурации Boot. -
${ROLLING_FILE_NAME_PATTERN}: Был ли установленlogging.pattern.rolling-file-nameво внешней конфигурации Boot.
Spring Boot также предоставляет приятный вывод ANSI-цвета в терминале консоли (но не в файле журнала) с помощью пользовательского преобразователя Logback. См. CONSOLE_LOG_PATTERN в defaults.xml конфигурации для примера.
Если Groovy находится в пути к классам, вы должны иметь возможность настроить Logback с помощью logback.groovy также. Если эта настройка присутствует, ей отдаётся предпочтение.
Расширения Spring не поддерживаются с конфигурацией Groovy. Любые файлы logback-spring.groovy не будут обнаружены. |
7.1.1. Настройка Logback для вывода только в файл
Если вы хотите отключить вывод в консоль и записывать вывод только в файл, вам нужна настраиваемая logback-spring.xml, которая импортирует file-appender.xml, но не console-appender.xml, как показано в следующем примере:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration> Вам также нужно добавить logging.file.name в вашу application.properties или application.yaml, как показано в следующем примере:
logging.file.name=myapplication.log logging:
file:
name: "myapplication.log" 7.2. Настройка Log4j для ведения журнала
Spring Boot поддерживает Log4j 2 для конфигурации ведения журнала, если он находится в пути к классам. Если вы используете стартеры для сборки зависимостей, вам нужно исключить Logback и затем включить Log4j 2 вместо него. Если вы не используете стартеры, вам необходимо предоставить (по крайней мере) spring-jcl в дополнение к Log4j 2.
Рекомендуемый путь — через стартеры, хотя это требует некоторых манипуляций. Следующий пример показывает, как настроить стартеры в Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency> Gradle предоставляет несколько способов настройки стартеров. Один способ — использовать замену модулей. Для этого объявите зависимость от стартера Log4j 2 и сообщите Gradle, что все случаи стандартного стартера ведения журнала должны быть заменены стартером Log4j 2, как показано в следующем примере:
dependencies {
implementation "org.springframework.boot:spring-boot-starter-log4j2"
modules {
module("org.springframework.boot:spring-boot-starter-logging") {
replacedBy("org.springframework.boot:spring-boot-starter-log4j2", "Use Log4j2 instead of Logback")
}
}
} Стартеры Log4j собирают зависимости для общих требований к ведению журнала (например, для того, чтобы Tomcat использовал java.util.logging, но настраивал вывод с помощью Log4j 2). |
Чтобы убедиться, что отладочный вывод ведения журнала, выполняемый с использованием java.util.logging, направляется в Log4j 2, настройте его адаптер JDK-логирования, установив системное свойство java.util.logging.manager в значение org.apache.logging.log4j.jul.LogManager. |
7.2.1. Использование YAML или JSON для конфигурации Log4j 2
Помимо стандартного формата конфигурации XML, Log4j 2 также поддерживает форматы YAML и JSON для файлов конфигурации. Для настройки Log4j 2 на использование альтернативного формата файла конфигурации добавьте соответствующие зависимости в путь к классам и назовите ваши файлы конфигурации в соответствии с выбранным форматом, как показано в следующем примере:
| Формат | Зависимости | Имена файлов |
|---|---|---|
YAML |
|
|
JSON |
|
|
7.2.2. Использование составной конфигурации для настройки Log4j 2
Log4j 2 поддерживает объединение нескольких файлов конфигурации в единую составную конфигурацию. Для использования этой поддержки в Spring Boot настройте logging.log4j2.config.override с расположениями одного или нескольких дополнительных файлов конфигурации. Дополнительные файлы конфигурации будут объединены с основной конфигурацией, независимо от того, является ли источник основной конфигурации параметрами по умолчанию Spring Boot, стандартным расположением, например log4j.xml, или расположением, настроенным свойством logging.config.
8. Доступ к данным
Spring Boot включает ряд стартеров для работы со источниками данных. В этом разделе рассматриваются вопросы, связанные с этим.
8.1. Настройка пользовательского источника данных
Для настройки собственного DataSource, определите @Bean такого типа в своей конфигурации. Spring Boot повторно использует ваш DataSource везде, где он требуется, включая инициализацию базы данных. Если вам нужно внешне задать некоторые параметры, вы можете привязать свой DataSource к среде (см. «features.html»).
Следующий пример показывает, как определить источник данных в компоненте:
@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {
@Bean
@ConfigurationProperties(prefix = "app.datasource")
public SomeDataSource dataSource() {
return new SomeDataSource();
}
}
@Configuration(proxyBeanMethods = false)
class MyDataSourceConfiguration {
@Bean
@ConfigurationProperties(prefix = "app.datasource")
fun dataSource(): SomeDataSource {
return SomeDataSource()
}
}
Следующий пример показывает, как определить источник данных, задав свойства:
app.datasource.url=jdbc:h2:mem:mydb
app.datasource.username=sa
app.datasource.pool-size=30 app:
datasource:
url: "jdbc:h2:mem:mydb"
username: "sa"
pool-size: 30 Предполагая, что SomeDataSource имеет обычные свойства JavaBean для URL, имени пользователя и размера пула, эти настройки автоматически привязываются перед тем, как DataSource станет доступным для других компонентов.
Spring Boot также предоставляет утилитарный класс-билдер, называемый DataSourceBuilder, который можно использовать для создания одного из стандартных источников данных (если он находится в классе). Библиотека может определить, какой использовать, исходя из того, что доступно в классе. Она также автоматически обнаруживает драйвер на основе JDBC URL.
Следующий пример показывает, как создать источник данных, используя DataSourceBuilder:
@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {
@Bean
@ConfigurationProperties("app.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
}
@Configuration(proxyBeanMethods = false)
class MyDataSourceConfiguration {
@Bean
@ConfigurationProperties("app.datasource")
fun dataSource(): DataSource {
return DataSourceBuilder.create().build()
}
}
Для запуска приложения с этим DataSource, вам нужны только данные подключения. Также можно указать параметры, специфичные для пула. Для получения дополнительной информации см. реализацию, используемую во время выполнения.
Следующий пример показывает, как определить источник данных JDBC, задав свойства:
app.datasource.url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.pool-size=30 app:
datasource:
url: "jdbc:mysql://localhost/test"
username: "dbuser"
password: "dbpass"
pool-size: 30 Однако есть подвох. Поскольку фактический тип пула подключений не показан, никакие ключи не генерируются в метаданных для вашего пользовательского DataSource, и нет возможности завершения в вашем IDE (поскольку интерфейс DataSource не содержит свойств). Кроме того, если у вас есть Hikari в классе, эта базовая настройка не работает, поскольку у Hikari нет свойства url (но есть свойство jdbcUrl). В этом случае необходимо переписать конфигурацию следующим образом:
app.datasource.jdbc-url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.pool-size=30 app:
datasource:
jdbc-url: "jdbc:mysql://localhost/test"
username: "dbuser"
password: "dbpass"
pool-size: 30 Вы можете исправить это, принудительно заставив пул подключений использовать и возвращать специальную реализацию, а не DataSource. Вы не можете изменить реализацию во время выполнения, но список вариантов будет явным.
Следующий пример показывает, как создать HikariDataSource с DataSourceBuilder:
@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {
@Bean
@ConfigurationProperties("app.datasource")
public HikariDataSource dataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
}
@Configuration(proxyBeanMethods = false)
class MyDataSourceConfiguration {
@Bean
@ConfigurationProperties("app.datasource")
fun dataSource(): HikariDataSource {
return DataSourceBuilder.create().type(HikariDataSource::class.java).build()
}
}
Вы даже можете пойти дальше, используя то, что делает DataSourceProperties за вас — то есть, предоставив по умолчанию встроенную базу данных с разумным именем пользователя и паролем, если URL не предоставлен. Вы можете легко инициализировать DataSourceBuilder из состояния любого объекта DataSourceProperties, поэтому вы также можете ввести DataSource, который Spring Boot создаёт автоматически. Однако это разделит вашу конфигурацию на два пространства имён: url, username, password, type и driver в spring.datasource, а остальное — в вашем пользовательском пространстве имён (app.datasource). Чтобы избежать этого, вы можете переопределить пользовательский DataSourceProperties в вашем пользовательском пространстве имён, как показано в следующем примере:
@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {
@Bean
@Primary
@ConfigurationProperties("app.datasource")
public DataSourceProperties dataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@ConfigurationProperties("app.datasource.configuration")
public HikariDataSource dataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
}
@Configuration(proxyBeanMethods = false)
class MyDataSourceConfiguration {
@Bean
@Primary
@ConfigurationProperties("app.datasource")
fun dataSourceProperties(): DataSourceProperties {
return DataSourceProperties()
}
@Bean
@ConfigurationProperties("app.datasource.configuration")
fun dataSource(properties: DataSourceProperties): HikariDataSource {
return properties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()
}
}
Эта настройка синхронизирует вас с тем, что Spring Boot делает по умолчанию, за исключением того, что выбран специальный пул подключений (в коде), и его настройки отображаются в подпространстве app.datasource.configuration. Поскольку DataSourceProperties заботится о переводе url/jdbcUrl за вас, вы можете настроить его следующим образом:
app.datasource.url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.configuration.maximum-pool-size=30 app:
datasource:
url: "jdbc:mysql://localhost/test"
username: "dbuser"
password: "dbpass"
configuration:
maximum-pool-size: 30 Spring Boot предоставит настройки, специфичные для Hikari, для spring.datasource.hikari. Этот пример использует более общее подпространство configuration, так как пример не поддерживает несколько реализаций источника данных. |
Поскольку ваша пользовательская конфигурация выбрала Hikari, app.datasource.type не имеет эффекта. На практике билдер инициализируется любым значением, которое вы можете установить, а затем переопределяется вызовом .type(). |
См. «data.html» в разделе «Функции Spring Boot» и класс DataSourceAutoConfiguration для получения дополнительной информации.
8.2. Настройка двух источников данных
Если вам нужно настроить несколько источников данных, вы можете применить те же приёмы, что описаны в предыдущем разделе. Однако вы должны пометить один из DataSource экземпляров как @Primary, потому что различные автоконфигурации в будущем ожидают получить один по типу.
Если вы создаёте собственный DataSource, автоконфигурация откатывается. В следующем примере мы предоставляем точно тот же набор функций, что и автоконфигурация для основного источника данных:
@Configuration(proxyBeanMethods = false)
public class MyDataSourcesConfiguration {
@Bean
@Primary
@ConfigurationProperties("app.datasource.first")
public DataSourceProperties firstDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@Primary
@ConfigurationProperties("app.datasource.first.configuration")
public HikariDataSource firstDataSource(DataSourceProperties firstDataSourceProperties) {
return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
@Bean
@ConfigurationProperties("app.datasource.second")
public BasicDataSource secondDataSource() {
return DataSourceBuilder.create().type(BasicDataSource.class).build();
}
}
@Configuration(proxyBeanMethods = false)
class MyDataSourcesConfiguration {
@Bean
@Primary
@ConfigurationProperties("app.datasource.first")
fun firstDataSourceProperties(): DataSourceProperties {
return DataSourceProperties()
}
@Bean
@Primary
@ConfigurationProperties("app.datasource.first.configuration")
fun firstDataSource(firstDataSourceProperties: DataSourceProperties): HikariDataSource {
return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()
}
@Bean
@ConfigurationProperties("app.datasource.second")
fun secondDataSource(): BasicDataSource {
return DataSourceBuilder.create().type(BasicDataSource::class.java).build()
}
}
firstDataSourceProperties должен быть помечен как @Primary, чтобы функция инициализатора базы данных использовала вашу копию (если вы используете инициализатор). |
Оба источника данных также привязаны для расширенных настроек. Например, вы можете настроить их следующим образом:
app.datasource.first.url=jdbc:mysql://localhost/first
app.datasource.first.username=dbuser
app.datasource.first.password=dbpass
app.datasource.first.configuration.maximum-pool-size=30
app.datasource.second.url=jdbc:mysql://localhost/second
app.datasource.second.username=dbuser
app.datasource.second.password=dbpass
app.datasource.second.max-total=30 app:
datasource:
first:
url: "jdbc:mysql://localhost/first"
username: "dbuser"
password: "dbpass"
configuration:
maximum-pool-size: 30
second:
url: "jdbc:mysql://localhost/second"
username: "dbuser"
password: "dbpass"
max-total: 30 Вы можете применить тот же принцип к второму DataSource, как показано в следующем примере:
@Configuration(proxyBeanMethods = false)
public class MyCompleteDataSourcesConfiguration {
@Bean
@Primary
@ConfigurationProperties("app.datasource.first")
public DataSourceProperties firstDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@Primary
@ConfigurationProperties("app.datasource.first.configuration")
public HikariDataSource firstDataSource(DataSourceProperties firstDataSourceProperties) {
return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
@Bean
@ConfigurationProperties("app.datasource.second")
public DataSourceProperties secondDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@ConfigurationProperties("app.datasource.second.configuration")
public BasicDataSource secondDataSource(
@Qualifier("secondDataSourceProperties") DataSourceProperties secondDataSourceProperties) {
return secondDataSourceProperties.initializeDataSourceBuilder().type(BasicDataSource.class).build();
}
}
@Configuration(proxyBeanMethods = false)
class MyCompleteDataSourcesConfiguration {
@Bean
@Primary
@ConfigurationProperties("app.datasource.first")
fun firstDataSourceProperties(): DataSourceProperties {
return DataSourceProperties()
}
@Bean
@Primary
@ConfigurationProperties("app.datasource.first.configuration")
fun firstDataSource(firstDataSourceProperties: DataSourceProperties): HikariDataSource {
return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()
}
@Bean
@ConfigurationProperties("app.datasource.second")
fun secondDataSourceProperties(): DataSourceProperties {
return DataSourceProperties()
}
@Bean
@ConfigurationProperties("app.datasource.second.configuration")
fun secondDataSource(secondDataSourceProperties: DataSourceProperties): BasicDataSource {
return secondDataSourceProperties.initializeDataSourceBuilder().type(BasicDataSource::class.java).build()
}
}
В приведенном выше примере настраиваются два источника данных в пользовательских пространствах имён с той же логикой, что Spring Boot использует в автоконфигурации. Обратите внимание, что каждое подпространство configuration предоставляет расширенные настройки, основанные на выбранной реализации.
8.3. Использование Spring Data Repositories
Spring Data может создавать реализации @Repository интерфейсов различных типов. Spring Boot обрабатывает всё это за вас, если эти @Repositories находятся в одном пакете (или подпакете) с вашим классом @EnableAutoConfiguration.
Для многих приложений достаточно добавить необходимые зависимости Spring Data в ваш класс. Существуют стартеры для JPA, Mongodb и другие стартеры для поддерживаемых технологий. Для начала создайте интерфейсы репозитория для обработки ваших объектов @Entity.
Spring Boot пытается угадать расположение ваших @Repository определений, основываясь на @EnableAutoConfiguration, которые он находит. Для большей гибкости используйте аннотацию @EnableJpaRepositories (из Spring Data JPA).
Для получения дополнительной информации о Spring Data см. страницу проекта Spring Data.
8.4. Отделение определений сущностей от конфигурации Spring
Spring Boot пытается угадать расположение ваших @Entity определений, основываясь на @EnableAutoConfiguration, которые он находит. Для большего контроля можно использовать аннотацию @EntityScan, как показано в следующем примере:
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@EntityScan(basePackageClasses = City.class)
public class MyApplication {
// ...
}
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@EntityScan(basePackageClasses = [City::class])
class MyApplication {
// ...
}
8.5. Настройка свойств JPA
Spring Data JPA уже предоставляет некоторые независимые от поставщика параметры конфигурации (например, для ведения журнала SQL), а Spring Boot экспонирует эти параметры и несколько дополнительных для Hibernate в качестве внешних свойств конфигурации. Некоторые из них автоматически обнаруживаются в соответствии с контекстом, поэтому вам не нужно их устанавливать.
Свойство spring.jpa.hibernate.ddl-auto является особым случаем, поскольку в зависимости от условий выполнения имеет разные значения по умолчанию. Если используется встроенная база данных и нет менеджера схемы (например, Liquibase или Flyway), который обрабатывает DataSource, он устанавливает значение по умолчанию create-drop. Во всех других случаях значение по умолчанию — none.
Диалект для использования определяется поставщиком JPA. Если вы предпочитаете указать диалект самостоятельно, задайте свойство spring.jpa.database-platform.
В следующем примере показаны наиболее распространенные параметры для установки:
spring.jpa.hibernate.naming.physical-strategy=com.example.MyPhysicalNamingStrategy
spring.jpa.show-sql=true spring:
jpa:
hibernate:
naming:
physical-strategy: "com.example.MyPhysicalNamingStrategy"
show-sql: true Кроме того, все свойства в spring.jpa.properties.* передаются как обычные свойства JPA (с удалённым префиксом) при создании локальной EntityManagerFactory.
| Необходимо убедиться, что имена, определённые в Например, если вы хотите настроить размер пакетной обработки Hibernate, вы должны использовать |
Если вам нужно применить расширенную настройку к свойствам Hibernate, рассмотрите возможность регистрации компонента HibernatePropertiesCustomizer, который будет вызван перед созданием EntityManagerFactory. Это имеет приоритет перед любыми настройками, применяемыми автоматической конфигурацией. |
8.6. Настройка стратегии именования Hibernate
Hibernate использует две разные стратегии именования для сопоставления имён из модели объектов с соответствующими именами в базе данных. Полное квалифицированное имя реализаций физической и неявной стратегий можно настроить, задав свойства spring.jpa.hibernate.naming.physical-strategy и spring.jpa.hibernate.naming.implicit-strategy соответственно. В качестве альтернативы, если компоненты ImplicitNamingStrategy или PhysicalNamingStrategy доступны в контексте приложения, Hibernate будет автоматически настроен на их использование.
По умолчанию Spring Boot настраивает физическую стратегию именования с помощью CamelCaseToUnderscoresNamingStrategy. Используя эту стратегию, все точки заменяются нижними подчёркиваниями, а верблюжьи обозначения — также. Кроме того, по умолчанию все имена таблиц генерируются в нижнем регистре. Например, сущность TelephoneNumber сопоставляется с таблицей telephone_number. Если ваша схема требует идентификаторов с разными регистрами, определите пользовательский компонент CamelCaseToUnderscoresNamingStrategy, как показано в следующем примере:
@Configuration(proxyBeanMethods = false)
public class MyHibernateConfiguration {
@Bean
public CamelCaseToUnderscoresNamingStrategy caseSensitivePhysicalNamingStrategy() {
return new CamelCaseToUnderscoresNamingStrategy() {
@Override
protected boolean isCaseInsensitive(JdbcEnvironment jdbcEnvironment) {
return false;
}
};
}
}
@Configuration(proxyBeanMethods = false)
class MyHibernateConfiguration {
@Bean
fun caseSensitivePhysicalNamingStrategy(): CamelCaseToUnderscoresNamingStrategy {
return object : CamelCaseToUnderscoresNamingStrategy() {
override fun isCaseInsensitive(jdbcEnvironment: JdbcEnvironment): Boolean {
return false
}
}
}
}
Если вы предпочитаете использовать по умолчанию Hibernate, задайте следующее свойство:
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl В качестве альтернативы, можно настроить следующий компонент:
@Configuration(proxyBeanMethods = false)
class MyHibernateConfiguration {
@Bean
PhysicalNamingStrategyStandardImpl caseSensitivePhysicalNamingStrategy() {
return new PhysicalNamingStrategyStandardImpl();
}
}
@Configuration(proxyBeanMethods = false)
internal class MyHibernateConfiguration {
@Bean
fun caseSensitivePhysicalNamingStrategy(): PhysicalNamingStrategyStandardImpl {
return PhysicalNamingStrategyStandardImpl()
}
}
См. HibernateJpaAutoConfiguration и JpaBaseConfiguration для получения более подробной информации.
8.7. Настройка кэширования второго уровня Hibernate
Hibernate кэш второго уровня может быть настроен для ряда поставщиков кэша. Вместо повторного поиска поставщика кэша Hibernate лучше предоставить его, если он доступен в контексте.
Для этого с JCache сначала убедитесь, что org.hibernate.orm:hibernate-jcache доступен в классе. Затем добавьте компонент HibernatePropertiesCustomizer, как показано в следующем примере:
@Configuration(proxyBeanMethods = false)
public class MyHibernateSecondLevelCacheConfiguration {
@Bean
public HibernatePropertiesCustomizer hibernateSecondLevelCacheCustomizer(JCacheCacheManager cacheManager) {
return (properties) -> properties.put(ConfigSettings.CACHE_MANAGER, cacheManager.getCacheManager());
}
}
@Configuration(proxyBeanMethods = false)
class MyHibernateSecondLevelCacheConfiguration {
@Bean
fun hibernateSecondLevelCacheCustomizer(cacheManager: JCacheCacheManager): HibernatePropertiesCustomizer {
return HibernatePropertiesCustomizer { properties ->
properties[ConfigSettings.CACHE_MANAGER] = cacheManager.cacheManager
}
}
}
Этот кастомизатор настроит Hibernate на использование того же CacheManager, что и в приложении. Также возможно использовать отдельные CacheManager экземпляры. Подробности см. в руководстве пользователя Hibernate.
8.8. Использование инъекции зависимостей в компонентах Hibernate
По умолчанию Spring Boot регистрирует реализацию BeanContainer, которая использует BeanFactory, чтобы преобразователи и слушатели сущностей могли использовать обычную инъекцию зависимостей.
Вы можете отключить или настроить это поведение, зарегистрировав компонент HibernatePropertiesCustomizer, который удалит или изменит свойство hibernate.resource.beans.container.
8.9. Использование пользовательского EntityManagerFactory
Чтобы полностью контролировать конфигурацию EntityManagerFactory, необходимо добавить компонент @Bean с именем ‘entityManagerFactory’. Spring Boot автоматически отключает свой менеджер сущностей в присутствии компонента такого типа.
8.10. Использование нескольких EntityManagerFactory
Если вам нужно использовать JPA с несколькими источниками данных, вам, скорее всего, понадобится по одному EntityManagerFactory на каждый источник данных. LocalContainerEntityManagerFactoryBean из Spring ORM позволяет настроить EntityManagerFactory для ваших нужд. Также можно повторно использовать JpaProperties для привязки настроек к каждому EntityManagerFactory, как показано в следующем примере:
@Configuration(proxyBeanMethods = false)
public class MyEntityManagerFactoryConfiguration {
@Bean
@ConfigurationProperties("app.jpa.first")
public JpaProperties firstJpaProperties() {
return new JpaProperties();
}
@Bean
public LocalContainerEntityManagerFactoryBean firstEntityManagerFactory(DataSource firstDataSource,
JpaProperties firstJpaProperties) {
EntityManagerFactoryBuilder builder = createEntityManagerFactoryBuilder(firstJpaProperties);
return builder.dataSource(firstDataSource).packages(Order.class).persistenceUnit("firstDs").build();
}
private EntityManagerFactoryBuilder createEntityManagerFactoryBuilder(JpaProperties jpaProperties) {
JpaVendorAdapter jpaVendorAdapter = createJpaVendorAdapter(jpaProperties);
return new EntityManagerFactoryBuilder(jpaVendorAdapter, jpaProperties.getProperties(), null);
}
private JpaVendorAdapter createJpaVendorAdapter(JpaProperties jpaProperties) {
// ... map JPA properties as needed
return new HibernateJpaVendorAdapter();
}
}
@Configuration(proxyBeanMethods = false)
class MyEntityManagerFactoryConfiguration {
@Bean
@ConfigurationProperties("app.jpa.first")
fun firstJpaProperties(): JpaProperties {
return JpaProperties()
}
@Bean
fun firstEntityManagerFactory(
firstDataSource: DataSource?,
firstJpaProperties: JpaProperties
): LocalContainerEntityManagerFactoryBean {
val builder = createEntityManagerFactoryBuilder(firstJpaProperties)
return builder.dataSource(firstDataSource).packages(Order::class.java).persistenceUnit("firstDs").build()
}
private fun createEntityManagerFactoryBuilder(jpaProperties: JpaProperties): EntityManagerFactoryBuilder {
val jpaVendorAdapter = createJpaVendorAdapter(jpaProperties)
return EntityManagerFactoryBuilder(jpaVendorAdapter, jpaProperties.properties, null)
}
private fun createJpaVendorAdapter(jpaProperties: JpaProperties): JpaVendorAdapter {
// ... map JPA properties as needed
return HibernateJpaVendorAdapter()
}
}
В примере выше создаётся EntityManagerFactory с использованием компонента DataSource с именем firstDataSource. Он сканирует сущности, расположенные в том же пакете, что и Order. Возможно сопоставление дополнительных свойств JPA с использованием пространства имён app.first.jpa.
Когда вы создаёте компонент для LocalContainerEntityManagerFactoryBean самостоятельно, любая настройка, применённая при создании автоматически настроенного LocalContainerEntityManagerFactoryBean, теряется. Например, в случае Hibernate, любые свойства с префиксом spring.jpa.hibernate не будут автоматически применены к вашему LocalContainerEntityManagerFactoryBean. Если вы полагались на эти свойства для настройки таких вещей, как стратегия именования или режим DDL, вам необходимо явно настроить их при создании компонента LocalContainerEntityManagerFactoryBean. |
Вы должны предоставить аналогичную конфигурацию для любых дополнительных источников данных, для которых вам нужен доступ к JPA. Для завершения картины, необходимо настроить JpaTransactionManager для каждого EntityManagerFactory также. В качестве альтернативы, возможно использование JTA менеджера транзакций, охватывающего оба.
Если вы используете Spring Data, вам необходимо настроить @EnableJpaRepositories соответствующим образом, как показано в следующих примерах:
@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = Order.class, entityManagerFactoryRef = "firstEntityManagerFactory")
public class OrderConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = [Order::class], entityManagerFactoryRef = "firstEntityManagerFactory")
class OrderConfiguration
@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = Customer.class, entityManagerFactoryRef = "secondEntityManagerFactory")
public class CustomerConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = [Customer::class], entityManagerFactoryRef = "secondEntityManagerFactory")
class CustomerConfiguration
8.11. Использование традиционного файла persistence.xml
Spring Boot по умолчанию не будет искать или использовать файл META-INF/persistence.xml. Если вы предпочитаете использовать традиционный файл persistence.xml, вам нужно определить собственный @Bean типа LocalEntityManagerFactoryBean (с идентификатором ‘entityManagerFactory’) и установить там имя persistence unit.
См. JpaBaseConfiguration для параметров по умолчанию.
8.12. Использование Spring Data JPA и Mongo репозиториев
Spring Data JPA и Spring Data Mongo могут автоматически создавать реализации Repository. Если оба присутствуют в classpath, возможно, потребуется дополнительная настройка, чтобы указать Spring Boot, какие репозитории создавать. Наиболее явным способом это сделать является использование стандартных аннотаций Spring Data @EnableJpaRepositories и @EnableMongoRepositories и указание расположения ваших интерфейсов Repository.
Также существуют флаги (spring.data.*.repositories.enabled и spring.data.*.repositories.type), которые можно использовать для включения и отключения автоматически настроенных репозиториев во внешней конфигурации. Это полезно, например, в случае, если вы хотите отключить Mongo репозитории и по-прежнему использовать автоматически настроенные MongoTemplate.
Такая же проблема и те же возможности существуют для других автоматически настраиваемых типов репозиториев Spring Data (Elasticsearch, Redis и других). Для работы с ними следует соответственно изменить названия аннотаций и флагов.
8.13. Настройка поддержки Spring Data в веб-приложениях
Spring Data предоставляет поддержку веб-приложений, упрощающую использование репозиториев Spring Data в веб-приложении. Spring Boot предоставляет свойства в пространстве имён spring.data.web для настройки конфигурации. Обратите внимание, что если вы используете Spring Data REST, необходимо использовать свойства в пространстве имён spring.data.rest.
8.14. Предоставление репозиториев Spring Data как REST-эндпоинтов
Spring Data REST может предоставить реализации Repository как REST-эндпоинты, при условии, что Spring MVC включен для приложения.
Spring Boot предоставляет набор полезных свойств (из пространства имён spring.data.rest), которые настраивают RepositoryRestConfiguration. Если требуется дополнительная настройка, необходимо использовать bean RepositoryRestConfigurer.
Если вы не указываете порядок для вашего пользовательского RepositoryRestConfigurer, он выполняется после того, как Spring Boot выполняет внутренний. Если необходимо указать порядок, убедитесь, что он выше 0. |
8.15. Настройка компонента, используемого JPA
Если вы хотите настроить компонент, используемый JPA, необходимо убедиться, что компонент инициализирован до JPA. Когда компонент настраивается автоматически, Spring Boot позаботится об этом за вас. Например, при автоматической настройке Flyway, Hibernate настраивается таким образом, чтобы зависеть от Flyway, что даёт Flyway возможность инициализировать базу данных перед тем, как Hibernate попытается её использовать.
Если вы настраиваете компонент самостоятельно, вы можете использовать подкласс EntityManagerFactoryDependsOnPostProcessor в качестве удобного способа настройки необходимых зависимостей. Например, если вы используете Hibernate Search с Elasticsearch в качестве менеджера индексов, все EntityManagerFactory бины должны быть настроены так, чтобы зависеть от elasticsearchClient бина, как показано в следующем примере:
/**
* {@link EntityManagerFactoryDependsOnPostProcessor} that ensures that
* {@link EntityManagerFactory} beans depend on the {@code elasticsearchClient} bean.
*/
@Component
public class ElasticsearchEntityManagerFactoryDependsOnPostProcessor
extends EntityManagerFactoryDependsOnPostProcessor {
public ElasticsearchEntityManagerFactoryDependsOnPostProcessor() {
super("elasticsearchClient");
}
}
@Component
class ElasticsearchEntityManagerFactoryDependsOnPostProcessor :
EntityManagerFactoryDependsOnPostProcessor("elasticsearchClient")
8.16. Настройка jOOQ с несколькими источниками данных
Если вам нужно использовать jOOQ с несколькими источниками данных, следует создать собственный DSLContext для каждого. Подробнее см. в JooqAutoConfiguration.
В частности, JooqExceptionTranslator и SpringTransactionProvider могут быть повторно использованы для предоставления аналогичных возможностей, которые обеспечивает автоматическая настройка с одним DataSource. |
9. Инициализация базы данных
Базу данных SQL можно инициализировать различными способами, в зависимости от используемой стека. Конечно, вы можете сделать это вручную, если база данных — отдельный процесс. Рекомендуется использовать единый механизм для генерации схемы.
9.1. Инициализация базы данных с помощью JPA
JPA предоставляет средства для генерации DDL, которые можно настроить на выполнение при запуске приложения на базе данных. Это контролируется двумя внешними свойствами:
-
spring.jpa.generate-ddl(boolean) включает и выключает эту функцию и является независимой от поставщика. -
spring.jpa.hibernate.ddl-auto(перечисление) — функция Hibernate, которая более точно управляет поведением. Эта функция описывается более подробно в этом руководстве.
9.2. Инициализация базы данных с помощью Hibernate
Вы можете явно установить spring.jpa.hibernate.ddl-auto, и стандартные значения свойства Hibernate — none, validate, update, create и create-drop. Spring Boot выбирает для вас значение по умолчанию, исходя из того, считает ли он вашу базу данных встроенной. По умолчанию это значение create-drop, если не обнаружен менеджер схем, или none во всех остальных случаях. Встроенная база данных определяется по типу Connection и URL JDBC. hsqldb, h2 и derby — кандидаты, а другие — нет. Будьте внимательны, переключаясь с памяти на «реальную» базу данных, чтобы не делать предположений о существовании таблиц и данных на новой платформе. Вам нужно явно установить ddl-auto или использовать один из других механизмов для инициализации базы данных.
Вы можете вывести создание схемы, включив логгер org.hibernate.SQL. Это делается автоматически, если включен режим отладки debug mode. |
Кроме того, файл с именем import.sql в корне classpath выполняется при запуске, если Hibernate создает схему с нуля (то есть, если свойство ddl-auto установлено в create или create-drop). Это может быть полезно для демонстраций и тестирования, но, скорее всего, не нужно оставлять его в classpath в рабочей среде. Это функция Hibernate (и не имеет ничего общего со Spring).
9.3. Инициализация базы данных с помощью простых SQL-скриптов
Spring Boot может автоматически создавать схему (скрипты DDL) вашей JDBC-базы данных DataSource или R2DBC-базы данных ConnectionFactory и инициализировать её данные (скрипты DML).
По умолчанию он загружает скрипты схемы из optional:classpath*:schema.sql, а скрипты данных — из optional:classpath*:data.sql. Местоположения этих скриптов схемы и данных могут быть настраиваемы с помощью spring.sql.init.schema-locations и spring.sql.init.data-locations соответственно. Префикс optional: означает, что приложение будет запускаться, даже если файлы отсутствуют. Чтобы приложение не запускалось, если файлы отсутствуют, удалите префикс optional:.
Кроме того, Spring Boot обрабатывает файлы optional:classpath*:schema-${platform}.sql и optional:classpath*:data-${platform}.sql (если они есть), где ${platform} — значение spring.sql.init.platform. Это позволяет переключаться на скрипты, специфичные для базы данных, при необходимости. Например, вы можете установить его в имя поставщика базы данных (hsqldb, h2, oracle, mysql, postgresql и так далее).
По умолчанию инициализация SQL-базы данных выполняется только при использовании встроенной базы данных памяти. Чтобы всегда инициализировать SQL-базу данных, независимо от её типа, установите spring.sql.init.mode в значение always. Аналогично, чтобы отключить инициализацию, установите spring.sql.init.mode в значение never. По умолчанию Spring Boot включает функцию быстрой ошибки (fail-fast) своего инициализатора базы данных на основе скриптов. Это означает, что если скрипты вызывают исключения, приложение не запускается. Вы можете настроить это поведение, установив spring.sql.init.continue-on-error.
Инициализация на основе скриптов DataSource выполняется по умолчанию до создания любых JPA-биндов EntityManagerFactory. schema.sql может быть использован для создания схемы для JPA-управляемых сущностей, а data.sql — для её заполнения. Хотя мы не рекомендуем использовать несколько технологий инициализации источников данных, если вы хотите, чтобы инициализация на основе скриптов DataSource строилась на основе создания схемы Hibernate, установите spring.jpa.defer-datasource-initialization в значение true. Это отложит инициализацию источника данных до создания и инициализации бинов EntityManagerFactory. schema.sql может быть использован для добавления к любому созданию схемы Hibernate, а data.sql — для заполнения.
Если вы используете инструмент миграции базы данных высокого уровня, такой как Flyway или Liquibase, используйте их для создания и инициализации схемы. Использование простых скриптов schema.sql и data.sql вместе с Flyway или Liquibase не рекомендуется, и поддержка будет удалена в будущих версиях.
9.4. Инициализация базы данных Spring Batch
Если вы используете Spring Batch, в нём уже есть SQL-скрипты инициализации для большинства популярных платформ баз данных. Spring Boot может определить тип вашей базы данных и выполнить эти скрипты при запуске. Если вы используете встроенную базу данных, это происходит по умолчанию. Вы также можете включить это для любого типа базы данных, как показано в следующем примере:
spring.batch.jdbc.initialize-schema=always spring:
batch:
jdbc:
initialize-schema: "always" Вы также можете отключить инициализацию явно, установив spring.batch.jdbc.initialize-schema в значение never.
9.5. Использование инструмента миграции базы данных высокого уровня
9.5.1. Выполнение миграций базы данных Flyway при запуске
Для автоматического выполнения миграций базы данных Flyway при запуске добавьте org.flywaydb:flyway-core в ваш classpath.
Обычно, миграции представляют собой скрипты в формате V<VERSION>__<NAME>.sql (с <VERSION>, разделяемым дефисом, например, ‘1’ или ‘2_1’). По умолчанию, они находятся в директории под названием classpath:db/migration, но вы можете изменить это расположение, задав spring.flyway.locations. Это список, разделенный запятыми, одного или нескольких classpath: или filesystem: расположений. Например, следующая конфигурация будет искать скрипты как в стандартном расположении classpath, так и в директории /opt/migration:
spring.flyway.locations=classpath:db/migration,filesystem:/opt/migration spring:
flyway:
locations: "classpath:db/migration,filesystem:/opt/migration" Вы также можете добавить специальный {vendor} плейсхолдер для использования скриптов, специфичных для поставщика. Предположим следующее:
spring.flyway.locations=classpath:db/migration/{vendor} spring:
flyway:
locations: "classpath:db/migration/{vendor}" Вместо использования db/migration, предыдущая конфигурация устанавливает используемую директорию в соответствии с типом базы данных (например, db/migration/mysql для MySQL). Список поддерживаемых баз данных доступен по адресу DatabaseDriver.
Миграции также могут быть написаны на Java. Flyway будет автоматически настроен с любыми компонентами, реализующими JavaMigration.
FlywayProperties предоставляет большинство настроек Flyway и небольшой набор дополнительных свойств, которые могут быть использованы для отключения миграций или отключения проверки расположения. Если вам нужен больший контроль над конфигурацией, рассмотрите регистрацию компонента FlywayConfigurationCustomizer.
Spring Boot вызывает Flyway.migrate() для выполнения миграции базы данных. Если вам нужен больший контроль, предоставьте @Bean, который реализует FlywayMigrationStrategy.
Flyway поддерживает SQL и Java обработчики событий. Для использования обработчиков на основе SQL поместите скрипты обработчиков в директорию classpath:db/migration. Для использования обработчиков на основе Java создайте один или несколько компонентов, реализующих Callback. Все такие компоненты автоматически регистрируются в Flyway. Они могут быть упорядочены с помощью @Order или путем реализации интерфейса Ordered. Компоненты, реализующие устаревший интерфейс FlywayCallback, также могут быть обнаружены, однако они не могут использоваться вместе с компонентами Callback.
По умолчанию, Flyway автоматически подключает (@Primary) DataSource в вашем контексте и использует его для миграций. Если вы хотите использовать другой DataSource, вы можете создать его и отметить его @Bean как @FlywayDataSource. Если вы это сделаете и хотите два источника данных, помните, что нужно создать ещё один и отметить его как @Primary. В качестве альтернативы, вы можете использовать собственный DataSource Flyway, задав spring.flyway.[url,user,password] во внешних свойствах. Установка любого из spring.flyway.url или spring.flyway.user достаточно для того, чтобы Flyway использовал свой собственный DataSource. Если ни одно из трёх свойств не установлено, будет использоваться значение соответствующего свойства spring.datasource.
Вы также можете использовать Flyway для предоставления данных для определённых сценариев. Например, вы можете поместить миграции, специфичные для тестов, в src/test/resources, и они будут выполняться только при запуске вашего приложения для тестирования. Также вы можете использовать конфигурацию, специфичную для профилей, чтобы настроить spring.flyway.locations таким образом, чтобы определённые миграции выполнялись только при активации определённого профиля. Например, в application-dev.properties, вы можете указать следующее значение:
spring.flyway.locations=classpath:/db/migration,classpath:/dev/db/migration spring:
flyway:
locations: "classpath:/db/migration,classpath:/dev/db/migration" С этой настройкой миграции в dev/db/migration выполняются только при активации профиля dev.
9.5.2. Выполнение миграций базы данных Liquibase при запуске
Для автоматического выполнения миграций базы данных Liquibase при запуске добавьте org.liquibase:liquibase-core в ваш classpath.
| Когда вы добавляете |
По умолчанию, главный журнал изменений считывается из db/changelog/db.changelog-master.yaml, но вы можете изменить расположение, задав spring.liquibase.change-log. Помимо YAML, Liquibase также поддерживает форматы JSON, XML и SQL для журнала изменений.
По умолчанию, Liquibase автоматически подключает (@Primary) DataSource в ваш контекст и использует его для миграций. Если вам нужно использовать другой DataSource, вы можете создать его и отметить его @Bean как @LiquibaseDataSource. Если вы это сделаете и хотите два источника данных, помните, что нужно создать ещё один и отметить его как @Primary. В качестве альтернативы, вы можете использовать собственный DataSource Liquibase, задав spring.liquibase.[driver-class-name,url,user,password] во внешних свойствах. Установка либо spring.liquibase.url, либо spring.liquibase.user достаточно для того, чтобы Liquibase использовал свой собственный DataSource. Если ни одно из трёх свойств не установлено, будет использоваться значение соответствующего свойства spring.datasource.
Подробную информацию о доступных настройках, таких как контексты, схема по умолчанию и другие, см. в LiquibaseProperties.
9.6. Зависимость от инициализированной базы данных
Инициализация базы данных выполняется при запуске приложения как часть обновления контекста приложения. Для доступа к инициализированной базе данных во время запуска приложения автоматически обнаруживаются компоненты, действующие как инициализаторы базы данных, и компоненты, которым требуется, чтобы база данных была инициализирована. Компоненты, инициализация которых зависит от того, была ли инициализирована база данных, настраиваются так, чтобы зависеть от тех, которые её инициализируют. Если во время запуска ваше приложение пытается получить доступ к базе данных, а она не была инициализирована, вы можете настроить дополнительное обнаружение компонентов, которые инициализируют базу данных и требуют её инициализации.
9.6.1. Обнаружение инициализатора базы данных
Spring Boot автоматически обнаружит компоненты следующих типов, которые инициализируют базу данных SQL:
-
DataSourceScriptDatabaseInitializer -
EntityManagerFactory -
Flyway -
FlywayMigrationInitializer -
R2dbcScriptDatabaseInitializer -
SpringLiquibase
Если вы используете сторонний стартер для библиотеки инициализации базы данных, он может предоставить детектор, который позволит автоматически обнаруживать компоненты и других типов. Чтобы обнаруживать другие компоненты, зарегистрируйте реализацию DatabaseInitializerDetector в META-INF/spring.factories.
9.6.2. Обнаружение компонента, зависящего от инициализации базы данных
Spring Boot автоматически обнаружит компоненты следующих типов, которые зависят от инициализации базы данных:
-
AbstractEntityManagerFactoryBean(еслиspring.jpa.defer-datasource-initializationне установлено вtrue) -
DSLContext(jOOQ) -
EntityManagerFactory(еслиspring.jpa.defer-datasource-initializationне установлено вtrue) -
JdbcOperations -
NamedParameterJdbcOperations
Если вы используете стороннюю библиотеку доступа к данным, она может предоставить детектор, который позволяет автоматически обнаруживать компоненты других типов. Чтобы обнаруживать другие компоненты, зарегистрируйте реализацию DependsOnDatabaseInitializationDetector в META-INF/spring.factories. В качестве альтернативы, отметьте класс компонента или его метод @Bean аннотацией @DependsOnDatabaseInitialization.
10. NoSQL
Spring Boot предлагает несколько стартеров, поддерживающих технологии NoSQL. В этом разделе рассматриваются вопросы, возникающие при использовании NoSQL с Spring Boot.
10.1. Использование Jedis вместо Lettuce
По умолчанию, стартер Spring Boot (spring-boot-starter-data-redis) использует Lettuce. Вам необходимо исключить эту зависимость и включить зависимость Jedis. Spring Boot управляет обеими этими зависимостями, поэтому вы можете переключиться на Jedis, не указывая версию.
Следующий пример демонстрирует, как это сделать в Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency> Следующий пример демонстрирует, как это сделать в Gradle:
dependencies {
implementation('org.springframework.boot:spring-boot-starter-data-redis') {
exclude group: 'io.lettuce', module: 'lettuce-core'
}
implementation 'redis.clients:jedis'
// ...
} 11. Сообщения
Spring Boot предлагает несколько стартеров для поддержки обмена сообщениями. В этом разделе рассматриваются вопросы, возникающие при использовании обмена сообщениями с Spring Boot.
11.1. Отключение транзакционных сессий JMS
Если ваш брокер JMS не поддерживает транзакционные сессии, вы должны полностью отключить поддержку транзакций. Если вы создаёте свой собственный JmsListenerContainerFactory, ничего делать не нужно, так как по умолчанию он не может быть транзакционным. Если вы хотите использовать DefaultJmsListenerContainerFactoryConfigurer для повторного использования значения по умолчанию Spring Boot, вы можете отключить транзакционные сессии следующим образом:
@Configuration(proxyBeanMethods = false)
public class MyJmsConfiguration {
@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory listenerFactory = new DefaultJmsListenerContainerFactory();
configurer.configure(listenerFactory, connectionFactory);
listenerFactory.setTransactionManager(null);
listenerFactory.setSessionTransacted(false);
return listenerFactory;
}
}
@Configuration(proxyBeanMethods = false)
class MyJmsConfiguration {
@Bean
fun jmsListenerContainerFactory(connectionFactory: ConnectionFactory?,
configurer: DefaultJmsListenerContainerFactoryConfigurer): DefaultJmsListenerContainerFactory {
val listenerFactory = DefaultJmsListenerContainerFactory()
configurer.configure(listenerFactory, connectionFactory)
listenerFactory.setTransactionManager(null)
listenerFactory.setSessionTransacted(false)
return listenerFactory
}
}
В приведенном примере переопределяется фабрика по умолчанию, и он должен применяться ко всем другим фабрикам, определённым в вашем приложении.
12. Приложения пакетной обработки
При использовании Spring Batch в приложении Spring Boot часто возникают вопросы. В этом разделе рассматриваются эти вопросы.
12.1. Указание источника данных для пакетной обработки
По умолчанию, приложения пакетной обработки требуют DataSource для хранения деталей задач. Spring Batch по умолчанию ожидает единственный DataSource. Чтобы использовать DataSource, отличный от основного DataSource приложения, объявите бин DataSource, аннотировав его метод @Bean аннотацией @BatchDataSource. Если вы это сделаете и хотите использовать два источника данных, не забудьте отметить другой @Primary. Для большего контроля добавьте @EnableBatchProcessing в один из ваших @Configuration классов или расширьте DefaultBatchConfiguration. Более подробную информацию см. в документации @EnableBatchProcessing и DefaultBatchConfiguration.
Для получения дополнительной информации о Spring Batch посетите страницу проекта Spring Batch.
12.2. Запуск задач Spring Batch при запуске
Автоконфигурация Spring Batch включается путём добавления spring-boot-starter-batch в ваш classpath.
Если в контексте приложения найдена единственная Job, она выполняется при запуске (см. JobLauncherApplicationRunner для подробностей). Если найдено несколько бин Job, задача, которая должна быть выполнена, должна быть указана с помощью spring.batch.job.name.
Чтобы отключить выполнение задачи Job, найденной в контексте приложения, установите spring.batch.job.enabled в false.
Для получения дополнительной информации см. BatchAutoConfiguration.
12.3. Запуск из командной строки
Spring Boot преобразует любой аргумент командной строки, начинающийся с --, в свойство, которое добавляется в Environment, см. доступ к свойствам командной строки. Это не следует использовать для передачи аргументов задачам пакетной обработки. Для указания аргументов пакетной обработки в командной строке используйте обычный формат (то есть без --), как показано в следующем примере:
$ java -jar myapp.jar someParameter=someValue anotherParameter=anotherValue Если вы укажете свойство Environment в командной строке, оно будет проигнорировано задачей. Рассмотрим следующую команду:
$ java -jar myapp.jar --server.port=7070 someParameter=someValue Это предоставляет только один аргумент задаче пакетной обработки: someParameter=someValue.
12.4. Хранение хранилища задач
Spring Batch требует хранилище данных для Job хранилища. Если вы используете Spring Boot, вам необходимо использовать фактическую базу данных. Обратите внимание, что это может быть база данных в памяти, см. Настройка хранилища задач.
13. Активатор
Spring Boot включает Spring Boot Активатор. В этом разделе отвечают на вопросы, которые часто возникают при его использовании.
13.1. Изменение порта или адреса HTTP-точек входа активатора
В автономном приложении порт HTTP-активатора по умолчанию совпадает с основным портом HTTP. Чтобы приложение прослушивало другой порт, установите внешнее свойство: management.server.port. Чтобы прослушивать другой сетевой адрес (например, когда у вас есть внутренняя сеть для управления и внешняя для пользовательских приложений), вы также можете установить management.server.address на допустимый IP-адрес, к которому сервер может подключиться.
Более подробную информацию можно найти в ManagementServerProperties исходном коде и в разделе «Готовые к работе функции» в «actuator.html».
13.2. Настройка страницы ошибки «whitelabel»
Spring Boot устанавливает страницу ошибки «whitelabel», которую вы видите в клиенте браузера, если возникает ошибка сервера (клиенты машин, потребляющие JSON и другие типы данных, должны видеть осмысленный ответ с правильным кодом ошибки).
Установите server.error.whitelabel.enabled=false, чтобы отключить страницу ошибки по умолчанию. Это восстановит настройки по умолчанию для используемого контейнера сервлетов. Обратите внимание, что Spring Boot по-прежнему пытается разрешить представление ошибки, поэтому вам, вероятно, следует добавить собственную страницу ошибки, а не полностью ее отключать. |
Переопределение страницы ошибки собственным шаблоном зависит от используемой вами технологии шаблонов. Например, если вы используете Thymeleaf, вы можете добавить шаблон error.html. Если вы используете FreeMarker, вы можете добавить шаблон error.ftlh. В общем случае вам нужен View, который разрешается с именем error или @Controller, который обрабатывает путь /error. Если вы не заменили некоторые настройки по умолчанию, вы должны найти BeanNameViewResolver в вашем ApplicationContext, поэтому @Bean с именем error будет одним из способов сделать это. Дополнительные параметры см. в ErrorMvcAutoConfiguration.
Также см. раздел «Обработка ошибок» для получения подробной информации о том, как регистрировать обработчики в контейнере сервлетов.
13.3. Санітизация конфіденційних значень
Информация, возвращаемая точками входа /env, /configprops и /quartz, может быть конфиденциальной. По умолчанию все значения санітизуются (заменяются на ******). Просмотр исходных значений в необработанном виде можно настроить для каждой точки входа с помощью свойства showValues для этой точки входа. Это свойство может быть настроено следующим образом:
-
ALWAYS- все значения отображаются в необработанном виде всем пользователям -
NEVER- все значения всегда санітизуются (заменяются на******) -
WHEN_AUTHORIZED- все значения отображаются в необработанном виде авторизованным пользователям
Для HTTP-точек входа пользователь считается авторизованным, если он прошел аутентификацию и имеет роли, настроенные свойством роли точки входа. По умолчанию любой аутентифицированный пользователь считается авторизованным. Для JMX-точек входа все пользователи всегда авторизованы.
management.endpoint.env.show-values=WHEN_AUTHORIZED
management.endpoint.env.roles=admin management:
endpoint:
env:
show-values: WHEN_AUTHORIZED
roles: "admin" Вышеуказанная настройка позволяет всем пользователям с ролью admin просматривать все значения в их исходном виде из точки входа /env.
Когда show-values установлено в ALWAYS или WHEN_AUTHORIZED, любая санітизация, применяемая SanitizingFunction, всё равно будет применена. |
13.3.1. Настройка санітизації
Чтобы получить контроль над санітизацией, определите бин SanitizingFunction. SanitizableData, с помощью которого вызывается функция, предоставляет доступ к ключу и значению, а также к PropertySource, откуда они пришли. Это позволяет, например, санітизировать каждое значение, которое поступает из определенного источника свойств. Каждый SanitizingFunction вызывается по порядку, пока функция не изменит значение санітизируемых данных.
13.4. Сопоставление индикаторов состояния с метриками Micrometer
Индикаторы состояния Spring Boot возвращают тип Status для обозначения общего состояния системы. Если вы хотите отслеживать или подавать сигналы тревоги по уровням состояния для конкретного приложения, вы можете экспортировать эти состояния как метрики с помощью Micrometer. По умолчанию Spring Boot использует коды состояния «UP», «DOWN», «OUT_OF_SERVICE» и «UNKNOWN». Чтобы их экспортировать, вам нужно преобразовать эти состояния в набор чисел, чтобы они могли использоваться с Micrometer Gauge.
Следующий пример демонстрирует один способ написания такого экспортера:
@Configuration(proxyBeanMethods = false)
public class MyHealthMetricsExportConfiguration {
public MyHealthMetricsExportConfiguration(MeterRegistry registry, HealthEndpoint healthEndpoint) {
// This example presumes common tags (such as the app) are applied elsewhere
Gauge.builder("health", healthEndpoint, this::getStatusCode).strongReference(true).register(registry);
}
private int getStatusCode(HealthEndpoint health) {
Status status = health.health().getStatus();
if (Status.UP.equals(status)) {
return 3;
}
if (Status.OUT_OF_SERVICE.equals(status)) {
return 2;
}
if (Status.DOWN.equals(status)) {
return 1;
}
return 0;
}
}
@Configuration(proxyBeanMethods = false)
class MyHealthMetricsExportConfiguration(registry: MeterRegistry, healthEndpoint: HealthEndpoint) {
init {
// This example presumes common tags (such as the app) are applied elsewhere
Gauge.builder("health", healthEndpoint) { health ->
getStatusCode(health).toDouble()
}.strongReference(true).register(registry)
}
private fun getStatusCode(health: HealthEndpoint): Int {
val status = health.health().status
if (Status.UP == status) {
return 3
}
if (Status.OUT_OF_SERVICE == status) {
return 2
}
if (Status.DOWN == status) {
return 1
}
return 0
}
}
14. Безопасность
В этом разделе рассматриваются вопросы безопасности при работе с Spring Boot, включая вопросы, возникающие при использовании Spring Security с Spring Boot.
Для получения дополнительной информации о Spring Security см. страницу проекта Spring Security.
14.1. Выключение конфигурации Spring Boot безопасности
Если вы определите @Configuration с бином SecurityFilterChain в своем приложении, это выключит настройки безопасности веб-приложений по умолчанию в Spring Boot.
14.2. Изменение UserDetailsService и добавление учетных записей пользователей
Если вы предоставите @Bean типа AuthenticationManager, AuthenticationProvider или UserDetailsService, по умолчанию @Bean для InMemoryUserDetailsManager не создается. Это означает, что у вас есть полный функционал Spring Security (например, различные варианты аутентификации).
Самый простой способ добавить учетные записи пользователей — предоставить собственный бин UserDetailsService.
14.3. Включение HTTPS при работе через прокси-сервер
Обеспечение того, что все основные точки входа доступны только по протоколу HTTPS, является важной задачей для любого приложения. Если вы используете Tomcat в качестве контейнера сервлетов, то Spring Boot автоматически добавляет собственный RemoteIpValve Tomcat, если он обнаруживает некоторые настройки среды, и вы можете полагаться на HttpServletRequest, чтобы сообщить, защищен ли он или нет (даже в случае с прокси-сервером, который выполняет фактическое завершение SSL). Стандартное поведение определяется наличием или отсутствием определенных заголовков запросов (x-forwarded-for и x-forwarded-proto), имена которых являются стандартными, поэтому это должно работать с большинством прокси-серверов фронтального типа. Вы можете включить клапан, добавив некоторые записи в application.properties, как показано в следующем примере:
server.tomcat.remoteip.remote-ip-header=x-forwarded-for
server.tomcat.remoteip.protocol-header=x-forwarded-proto server:
tomcat:
remoteip:
remote-ip-header: "x-forwarded-for"
protocol-header: "x-forwarded-proto" (Наличие любого из этих свойств включает клапан. В качестве альтернативы, вы можете добавить RemoteIpValve, настроив TomcatServletWebServerFactory с помощью бинa WebServerFactoryCustomizer.)
Чтобы настроить Spring Security таким образом, чтобы потребовать защищенный канал для всех (или некоторых) запросов, рассмотрите возможность добавления собственного бинa SecurityFilterChain, который добавляет следующие настройки HttpSecurity:
@Configuration
public class MySecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// Customize the application security ...
http.requiresChannel((channel) -> channel.anyRequest().requiresSecure());
return http.build();
}
}
@Configuration
class MySecurityConfig {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
// Customize the application security ...
http.requiresChannel { requests -> requests.anyRequest().requiresSecure() }
return http.build()
}
}
15. Горячая замена
Spring Boot поддерживает горячую замену. В этом разделе рассматриваются вопросы о том, как она работает.
15.1. Перезагрузка статического контента
Существует несколько вариантов горячей перезагрузки. Рекомендуемый подход — использовать spring-boot-devtools, так как он предоставляет дополнительные функции для разработки, такие как поддержка быстрой перезагрузки приложения и LiveReload, а также разумная конфигурация для разработки (например, кэширование шаблонов). Devtools отслеживает изменения в classpath. Это означает, что изменения в статических ресурсах должны быть «собраны», чтобы изменения вступили в силу. По умолчанию это происходит автоматически в Eclipse при сохранении изменений. В IntelliJ IDEA команда «Собрать проект» запускает необходимую сборку. Из-за исключений перезагрузки по умолчанию изменения в статических ресурсах не приводят к перезагрузке приложения. Однако они запускают живую перезагрузку.
В качестве альтернативы, работа в IDE (особенно с отладкой) — хороший способ разработки (все современные IDE позволяют перезагружать статические ресурсы и обычно также позволяют выполнять горячую замену изменений в классах Java).
Наконец, плагины Maven и Gradle можно настроить (см. свойство addResources), чтобы поддерживать выполнение из командной строки с перезагрузкой статических файлов непосредственно из исходного кода. Вы можете использовать это с внешним процессом компиляции css/js, если вы пишете этот код с помощью инструментов более высокого уровня.
15.2. Перезагрузка шаблонов без перезапуска контейнера
Большинство технологий шаблонизации, поддерживаемых Spring Boot, включают возможность отключения кэширования (описано далее в этом документе). Если вы используете модуль spring-boot-devtools, эти свойства автоматически настраиваются для вас во время разработки.
15.2.1. Шаблоны Thymeleaf
Если вы используете Thymeleaf, установите spring.thymeleaf.cache в false. См. ThymeleafAutoConfiguration для других параметров настройки Thymeleaf.
15.2.2. Шаблоны FreeMarker
Если вы используете FreeMarker, установите spring.freemarker.cache в false. См. FreeMarkerAutoConfiguration для других параметров настройки FreeMarker.
15.2.3. Шаблоны Groovy
Если вы используете шаблоны Groovy, установите spring.groovy.template.cache в false. См. GroovyTemplateAutoConfiguration для других параметров настройки Groovy.
15.3. Быстрая перезагрузка приложения
Модуль spring-boot-devtools включает поддержку автоматической перезагрузки приложения. Хотя он не такой быстрый, как технологии, такие как JRebel, обычно он значительно быстрее, чем «холодный запуск». Попробуйте его перед изучением более сложных вариантов перезагрузки, обсуждаемых позже в этом документе.
Для получения более подробной информации см. раздел using.html.
15.4. Перезагрузка классов Java без перезапуска контейнера
Многие современные IDE (Eclipse, IDEA и другие) поддерживают горячую замену байткода. Следовательно, если вы внесли изменение, не повлиявшее на подписи классов или методов, оно должно перезагружаться без побочных эффектов.
16. Тестирование
Spring Boot включает в себя ряд инструментов и вспомогательных классов для тестирования, а также специальный стартер, который предоставляет общие зависимости для тестов. В этом разделе рассматриваются распространённые вопросы, связанные с тестированием.
16.1. Тестирование с Spring Security
Spring Security предоставляет поддержку запуска тестов как определённого пользователя. Например, тест в приведённом ниже фрагменте будет выполняться с аутентифицированным пользователем, имеющим роль ADMIN.
@WebMvcTest(UserController.class)
class MySecurityTests {
@Autowired
private MockMvc mvc;
@Test
@WithMockUser(roles = "ADMIN")
void requestProtectedUrlWithUser() throws Exception {
this.mvc.perform(get("/"));
}
}
@WebMvcTest(UserController::class)
class MySecurityTests(@Autowired val mvc: MockMvc) {
@Test
@WithMockUser(roles = ["ADMIN"])
fun requestProtectedUrlWithUser() {
mvc.perform(MockMvcRequestBuilders.get("/"))
}
}
Spring Security обеспечивает полную интеграцию с Spring MVC Test, и это также можно использовать при тестировании контроллеров с использованием среза @WebMvcTest и MockMvc.
Дополнительные сведения о поддержке тестирования Spring Security см. в справочной документации Spring Security здесь.
16.2. Структура @Configuration классов для включения в срезы тестов
Срезы тестов работают путём ограничения сканирования компонентов Spring Framework до ограниченного набора компонентов на основе их типа. Для любых бинов, которые не создаются через сканирование компонентов, например, бинов, созданных с использованием аннотации @Bean, срезы тестов не смогут включать/исключать их из контекста приложения. Рассмотрим пример:
@Configuration(proxyBeanMethods = false)
public class MyConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());
return http.build();
}
@Bean
@ConfigurationProperties("app.datasource.second")
public BasicDataSource secondDataSource() {
return DataSourceBuilder.create().type(BasicDataSource.class).build();
}
}
Для @WebMvcTest приложения с указанным выше классом @Configuration, вы могли бы ожидать наличия бинa SecurityFilterChain в контексте приложения, чтобы вы могли проверить, защищены ли правильно ваши контроллерные конечные точки. Однако MyConfiguration не обнаруживается фильтром сканирования компонентов @WebMvcTest, поскольку он не соответствует ни одному из типов, указанных в фильтре. Вы можете явно включить конфигурацию, аннотировав класс теста @Import(MyConfiguration.class). Это загрузит все бины в MyConfiguration, включая бин BasicDataSource, который не требуется при тестировании веб-уровня. Разделение класса конфигурации на два позволит импортировать только конфигурацию безопасности.
@Configuration(proxyBeanMethods = false)
public class MySecurityConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());
return http.build();
}
}
@Configuration(proxyBeanMethods = false)
public class MyDatasourceConfiguration {
@Bean
@ConfigurationProperties("app.datasource.second")
public BasicDataSource secondDataSource() {
return DataSourceBuilder.create().type(BasicDataSource.class).build();
}
}
Использование одного класса конфигурации может быть неэффективным, когда бины определённого домена должны быть включены в срезы тестов. Вместо этого структурирование конфигурации приложения как нескольких гранулированных классов с бинами для определённого домена может позволить импортировать их только для конкретных срезов тестов.
17. Сборка
Spring Boot включает плагины сборки для Maven и Gradle. В этом разделе отвечены на часто задаваемые вопросы об этих плагинах.
17.1. Генерация информации о сборке
Плагин Maven и плагин Gradle позволяют генерировать информацию о сборке, содержащую координаты, имя и версию проекта. Плагины также могут быть настроены для добавления дополнительных свойств через конфигурацию. При наличии такого файла Spring Boot автоматически настраивает bean BuildProperties.
Для генерации информации о сборке с помощью Maven добавьте выполнение для цели build-info, как показано в следующем примере:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.1.3</version>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build> | Подробнее см. в документации плагина Spring Boot Maven. |
Следующий пример делает то же самое с Gradle:
springBoot {
buildInfo()
} | Подробнее см. в документации плагина Spring Boot Gradle. |
17.2. Генерация информации из Git
И Maven, и Gradle позволяют генерировать файл git.properties, содержащий информацию о состоянии вашего репозитория исходного кода git во время сборки проекта.
Для пользователей Maven, в файле spring-boot-starter-parent POM включен предварительно настроенный плагин для генерации файла git.properties. Для его использования добавьте следующее объявление для Git Commit Id Plugin в ваш POM:
<build>
<plugins>
<plugin>
<groupId>io.github.git-commit-id</groupId>
<artifactId>git-commit-id-maven-plugin</artifactId>
</plugin>
</plugins>
</build> Пользователи Gradle могут достичь того же результата, используя плагин gradle-git-properties, как показано в следующем примере:
plugins {
id "com.gorylenko.gradle-git-properties" version "2.4.1"
} Оба плагина Maven и Gradle позволяют настраивать свойства, включенные в git.properties.
Время коммита в git.properties должно соответствовать следующему формату: yyyy-MM-dd’T’HH:mm:ssZ. Это стандартный формат для обоих плагинов, указанных выше. Использование этого формата позволяет парсить время в Date и его формат, при сериализации в JSON, управлять настройками сериализации дат Jackson. |
17.3. Настройка версий зависимостей
Файл spring-boot-dependencies POM управляет версиями общих зависимостей. Плагины Spring Boot для Maven и Gradle позволяют настраивать эти управляемые версии зависимостей с помощью свойств сборки.
| Каждый выпуск Spring Boot разработан и протестирован с этим конкретным набором сторонних зависимостей. Изменение версий может привести к проблемам совместимости. |
Для переопределения версий зависимостей с помощью Maven, см. данный раздел в документации плагина Maven.
Для переопределения версий зависимостей в Gradle, см. данный раздел в документации плагина Gradle.
17.4. Создание исполняемого JAR-файла с помощью Maven
spring-boot-maven-plugin может использоваться для создания исполняемого "fat" JAR. Если вы используете spring-boot-starter-parent POM, вы можете объявить плагин, и ваши JAR-файлы будут переупакованы следующим образом:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> Если вы не используете родительский POM, вы все равно можете использовать плагин. Однако вам необходимо дополнительно добавить раздел <executions>, как показано ниже:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.1.3</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build> Полные детали использования см. в документации плагина.
17.5. Использование приложения Spring Boot в качестве зависимости
Как и WAR-файл, приложение Spring Boot не предназначено для использования в качестве зависимости. Если ваше приложение содержит классы, которые вы хотите использовать в других проектах, рекомендуется переместить этот код в отдельный модуль. Затем отдельный модуль можно использовать в вашем приложении и других проектах.
Если вы не можете перегруппировать свой код, как рекомендовано выше, плагины Spring Boot для Maven и Gradle должны быть настроены для создания отдельного артефакта, подходящего для использования в качестве зависимости. Исполняемый архив не может быть использован в качестве зависимости, так как формат исполняемого JAR-файла упаковывает классы приложения в BOOT-INF/classes. Это означает, что их нельзя найти, когда исполняемый JAR используется как зависимость.
Для создания двух артефактов, одного для использования в качестве зависимости и одного для выполнения, необходимо указать классификатор. Этот классификатор применяется к имени исполняемого архива, оставляя по умолчанию архив для использования в качестве зависимости.
Для настройки классификатора exec в Maven вы можете использовать следующую конфигурацию:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
</build> 17.6. Извлечение определенных библиотек при запуске исполняемого JAR
Большинство вложенных библиотек в исполняемом JAR не нуждаются в распаковке для работы. Однако у некоторых библиотек могут возникнуть проблемы. Например, JRuby включает свою собственную поддержку вложенных JAR, предполагая, что jruby-complete.jar всегда непосредственно доступен в виде файла сам по себе.
Чтобы справиться с проблемами библиотек, вы можете отметить, что определенные вложенные JAR должны быть автоматически распакованы при первом запуске исполняемого JAR. Такие вложенные JAR пишутся в временной директории, определяемой системной переменной java.io.tmpdir.
| Следует позаботиться о том, чтобы ваша операционная система была настроена так, чтобы не удалять распакованные JAR-файлы в временную директорию, пока приложение работает. |
Например, чтобы указать, что JRuby должен быть помечен для распаковки с использованием плагина Maven, вы добавите следующую конфигурацию:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<requiresUnpack>
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby-complete</artifactId>
</dependency>
</requiresUnpack>
</configuration>
</plugin>
</plugins>
</build> 17.7. Создание неисполняемого JAR с исключениями
Часто, если у вас есть исполняемый и неисполняемый JAR в качестве двух отдельных продуктов сборки, исполняемая версия имеет дополнительные конфигурационные файлы, которые не нужны в библиотечном JAR. Например, конфигурационный файл application.yaml может быть исключен из неисполняемого JAR.
В Maven, исполняемый JAR должен быть основным артефактом, и вы можете добавить классифицированный JAR для библиотеки следующим образом:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>lib</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>lib</classifier>
<excludes>
<exclude>application.yaml</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build> 17.8. Дистанционная отладка приложения Spring Boot, запущенного с Maven
Для подключения удаленного отладчика к приложению Spring Boot, запущенному с Maven, вы можете использовать свойство jvmArguments плагина Maven.
См. этот пример для получения более подробной информации.
17.9. Сборка исполняемого архива с помощью Ant без использования spring-boot-antlib
Для сборки с помощью Ant, вам необходимо получить зависимости, скомпилировать и затем создать JAR- или WAR-архив. Для того, чтобы сделать его исполняемым, вы можете либо использовать модуль spring-boot-antlib, либо следовать этим инструкциям:
-
Если вы собираете JAR, упакуйте классы и ресурсы приложения в вложенную директорию
BOOT-INF/classes. Если вы собираете WAR, упакуйте классы приложения в вложенную директориюWEB-INF/classes, как обычно. -
Добавьте зависимости времени выполнения в вложенную директорию
BOOT-INF/libдля JAR илиWEB-INF/libдля WAR. Не забудьте не сжимать записи в архиве. -
Добавьте зависимости
provided(встроенного контейнера) в вложенную директориюBOOT-INF/libдля JAR илиWEB-INF/lib-providedдля WAR. Не забудьте не сжимать записи в архиве. -
Добавьте классы
spring-boot-loaderв корень архива (чтобыMain-Classбыл доступен). -
Используйте соответствующий загрузчик (например,
JarLauncherдля JAR-файла) в качестве атрибутаMain-Classв манифесте и укажите необходимые свойства, как записи в манифесте — в основном, установив свойствоStart-Class.
Следующий пример показывает, как собрать исполняемый архив с помощью Ant:
<target name="build" depends="compile">
<jar destfile="target/${ant.project.name}-${spring-boot.version}.jar" compress="false">
<mappedresources>
<fileset dir="target/classes" />
<globmapper from="*" to="BOOT-INF/classes/*"/>
</mappedresources>
<mappedresources>
<fileset dir="src/main/resources" erroronmissingdir="false"/>
<globmapper from="*" to="BOOT-INF/classes/*"/>
</mappedresources>
<mappedresources>
<fileset dir="${lib.dir}/runtime" />
<globmapper from="*" to="BOOT-INF/lib/*"/>
</mappedresources>
<zipfileset src="${lib.dir}/loader/spring-boot-loader-jar-${spring-boot.version}.jar" />
<manifest>
<attribute name="Main-Class" value="org.springframework.boot.loader.JarLauncher" />
<attribute name="Start-Class" value="${start-class}" />
</manifest>
</jar>
</target> 18. Предварительная обработка
Возникает ряд вопросов при использовании предварительной обработки приложений Spring Boot. В этом разделе рассматриваются эти вопросы.
18.1. Условия
Предварительная обработка оптимизирует приложение и оценивает условия на основе среды во время сборки. Профили реализованы через условия и также на них влияют.
Если вам нужны компоненты, созданные на основе условия в оптимизированном приложении предварительной обработки, необходимо настроить среду при сборке приложения. Компоненты, созданные во время предварительной обработки на этапе сборки, всегда создаются при запуске приложения и не могут быть отключены. Для этого можно установить профили, которые должны использоваться при сборке приложения.
Для Maven это делается путем настройки конфигурации profiles выполнения spring-boot-maven-plugin:process-aot:
<profile>
<id>native</id>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>process-aot</id>
<configuration>
<profiles>profile-a,profile-b</profiles>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile> Для Gradle необходимо настроить задачу ProcessAot:
tasks.withType(org.springframework.boot.gradle.tasks.aot.ProcessAot).configureEach {
args('--spring.profiles.active=profile-a,profile-b')
} Профили, которые изменяют только свойства конфигурации, не влияющие на условия, поддерживаются без ограничений при запуске оптимизированных приложений предварительной обработки.
19. Традиционная развертывание
Spring Boot поддерживает традиционную развертку, а также более современные формы развертывания. Этот раздел отвечает на часто задаваемые вопросы о традиционной развертке.
19.1. Создание развертываемого файла WAR
| Поскольку Spring WebFlux не строго зависит от API сервлетов, а приложения по умолчанию развертываются на встроенном сервере Reactor Netty, развертывание WAR для приложений WebFlux не поддерживается. |
Первый шаг в создании развертываемого файла WAR — предоставить подкласс SpringBootServletInitializer и переопределить его метод configure. Это позволяет использовать поддержку сервлетов 3.0 Spring Framework и настраивать приложение при запуске контейнером сервлетов. Обычно, вы должны обновить главный класс вашего приложения, чтобы он расширял класс SpringBootServletInitializer, как показано в следующем примере:
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MyApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
@SpringBootApplication
class MyApplication : SpringBootServletInitializer() {
override fun configure(application: SpringApplicationBuilder): SpringApplicationBuilder {
return application.sources(MyApplication::class.java)
}
}
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
}
Следующий шаг — обновить конфигурацию сборки таким образом, чтобы ваш проект генерировал файл WAR, а не JAR. Если вы используете Maven и spring-boot-starter-parent (который настраивает плагин Maven для создания WAR), вам нужно только изменить pom.xml, чтобы изменить упаковку на war, как показано ниже:
<packaging>war</packaging> Если вы используете Gradle, вам нужно изменить build.gradle, чтобы применить плагин war к проекту, как показано ниже:
apply plugin: 'war' Последний шаг — убедиться, что встроенный контейнер сервлетов не конфликтует с контейнером сервлетов, в который развертывается файл WAR. Для этого вам нужно пометить зависимость встроенного контейнера сервлетов как provided.
Если вы используете Maven, следующий пример отмечает контейнер сервлетов (Tomcat, в данном случае) как provided:
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- ... -->
</dependencies> Если вы используете Gradle, следующий пример отмечает контейнер сервлетов (Tomcat, в данном случае) как provided:
dependencies {
// ...
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
// ...
} Предпочтительно использовать способ маркировки зависимостей встроенного контейнера сервлетов как provided с помощью providedRuntime, а не конфигурацию compileOnly в Gradle. Среди прочих ограничений, зависимости compileOnly не находятся в пути к тестовым классам, поэтому любые веб-интеграционные тесты завершаются сбоем. |
Если вы используете инструменты сборки Spring Boot, маркировка зависимости встроенного контейнера сервлетов как provided создает исполняемый файл WAR с зависимостями provided, упакованными в каталог lib-provided. Это означает, что, помимо развертывания в контейнер сервлетов, вы также можете запустить ваше приложение, используя java -jar в командной строке.
19.2. Преобразование существующего приложения в Spring Boot
Для преобразования существующего не-веб-приложения Spring в приложение Spring Boot замените код, который создаёт ваш ApplicationContext, вызовами SpringApplication или SpringApplicationBuilder. Веб-приложения Spring MVC обычно можно сначала преобразовать в развертываемое приложение war, а затем позже переместить его в исполняемый war или jar. См. Руководство по началу работы по преобразованию jar в war.
Для создания развертываемого файла WAR, расширив класс SpringBootServletInitializer (например, в классе с именем Application) и добавив аннотацию Spring Boot @SpringBootApplication, используйте код, подобный следующему примеру:
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
// Customize the application or call application.sources(...) to add sources
// Since our example is itself a @Configuration class (through
// @SpringBootApplication)
// we actually do not need to override this method.
return application;
}
}
@SpringBootApplication
class MyApplication : SpringBootServletInitializer() {
override fun configure(application: SpringApplicationBuilder): SpringApplicationBuilder {
// Customize the application or call application.sources(...) to add sources
// Since our example is itself a @Configuration class (through @SpringBootApplication)
// we actually do not need to override this method.
return application
}
}
Помните, что всё, что вы помещаете в sources, представляет собой всего лишь Spring ApplicationContext. Как правило, всё, что уже работает, должно работать и здесь. Возможно, некоторые бинны можно удалить позже, и Spring Boot предоставит свои собственные значения по умолчанию, но, скорее всего, можно получить работающий результат, прежде чем нужно будет что-то менять.
Статические ресурсы можно перенести в /public (или /static или /resources или /META-INF/resources) в корне пути к классам. То же самое относится к messages.properties (который Spring Boot автоматически обнаруживает в корне пути к классам).
Простая интеграция Spring DispatcherServlet и Spring Security не потребует дополнительных изменений. Если в вашем приложении используются другие функции (например, другие сервлеты или фильтры), вам может потребоваться добавить некоторую конфигурацию в контекст Application, заменив соответствующие элементы из web.xml, как показано ниже:
-
@BeanтипаServletилиServletRegistrationBeanустанавливает этот бин в контейнер так, как если бы это был<servlet/>и<servlet-mapping/>вweb.xml. -
@BeanтипаFilterилиFilterRegistrationBeanведёт себя аналогично (как<filter/>и<filter-mapping/>). -
ApplicationContextв файле XML можно добавить с помощью@ImportResourceв вашемApplication. Кроме того, случаи, где аннотациями используется уже большая часть конфигурации, можно переделать в несколько строк как определения@Bean.
После того, как файл WAR начнёт работать, вы можете сделать его исполняемым, добавив метод main в ваш класс Application, как показано в следующем примере:
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
}
| Если вы хотите запускать приложение как war, так и как исполняемое приложение, вам нужно разделить настройки билдера в методе, который доступен как в callback Java Kotlin |
Приложения могут относиться к нескольким категориям:
-
Приложения Servlet 3.0+ без
web.xml. -
Приложения с
web.xml. -
Приложения с иерархией контекстов.
-
Приложения без иерархии контекстов.
Все они должны поддаваться преобразованию, но для каждого из них могут потребоваться немного отличающиеся методы.
Приложения Servlet 3.0+ могут преобразовываться довольно легко, если они уже используют поддержку Spring Servlet 3.0+ инициализаторов классов. Обычно, весь код из существующего WebApplicationInitializer можно перенести в SpringBootServletInitializer. Если у вашего существующего приложения есть более одного ApplicationContext (например, если оно использует AbstractDispatcherServletInitializer), то, возможно, вы сможете объединить все источники контекста в один SpringApplication. Основная сложность может возникнуть, если объединение не работает, и вам нужно сохранить иерархию контекстов. См. запись о создании иерархии для примеров. Существующий родительский контекст, содержащий веб-специфические функции, обычно необходимо разбить таким образом, чтобы все компоненты ServletContextAware были в дочернем контексте.
Приложения, которые не являются приложениями Spring, могут быть преобразованы в приложения Spring Boot, и вышеупомянутые рекомендации могут помочь. Однако, могут возникнуть проблемы. В этом случае мы рекомендуем задать вопросы на Stack Overflow с тегом spring-boot.
19.3. Развертывание WAR в WebLogic
Для развертывания приложения Spring Boot в WebLogic необходимо убедиться, что ваш инициализатор сервлетов прямо реализует интерфейс WebApplicationInitializer (даже если вы наследуете от базового класса, который его уже реализует).
Типичный инициализатор для WebLogic должен быть похожим на следующий пример:
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer implements WebApplicationInitializer {
}
@SpringBootApplication
class MyApplication : SpringBootServletInitializer(), WebApplicationInitializer
Если вы используете Logback, вам также нужно указать WebLogic, чтобы он предпочитал упакованную версию, а не предварительно установленную версию с сервера. Вы можете сделать это, добавив файл WEB-INF/weblogic.xml со следующим содержимым:
<?xml version="1.0" encoding="UTF-8"?>
<wls:weblogic-web-app
xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
https://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd
http://xmlns.oracle.com/weblogic/weblogic-web-app
https://xmlns.oracle.com/weblogic/weblogic-web-app/1.4/weblogic-web-app.xsd">
<wls:container-descriptor>
<wls:prefer-application-packages>
<wls:package-name>org.slf4j</wls:package-name>
</wls:prefer-application-packages>
</wls:container-descriptor>
</wls:weblogic-web-app> 20. Docker Compose
Этот раздел включает темы, связанные с поддержкой Docker Compose в Spring Boot.
20.1. Настройка JDBC URL
При использовании JdbcConnectionDetails с Docker Compose, параметры JDBC URL можно настроить, применив метку org.springframework.boot.jdbc.parameters к сервису. Например:
services:
postgres:
image: 'postgres:15.3'
environment:
- 'POSTGRES_USER=myuser'
- 'POSTGRES_PASSWORD=secret'
- 'POSTGRES_DB=mydb'
ports:
- '5432:5432'
labels:
org.springframework.boot.jdbc.parameters: 'ssl=true&sslmode=require' С этим файлом Docker Compose, используемый JDBC URL будет jdbc:postgresql://127.0.0.1:5432/mydb?ssl=true&sslmode=require.
Copyright © 2012-2023 VMware, Inc.
Licensed under the Apache License, Version 2.0.
https://docs.spring.io/spring-boot/docs/3.1.3/reference/html/howto.html