1. Spring Initializr как старт проекта
Если вы когда-нибудь начинали проект «с нуля» в пустой директории, вы знаете эту стадию: пять минут уходят на создание папок, потом два часа — на выбор названия модуля, ещё час — на подключение зависимостей… а код приложения так и не появился. Для новичка это особенно неприятно: решений много, большинство выглядят одинаково, а ошибки проявляются позже. Spring Initializr существует именно для того, чтобы старт был быстрым, стандартным и воспроизводимым, а вы могли думать о приложении, а не о ритуалах.
Spring Initializr — это не «кнопка, которая делает магию», а генератор аккуратного шаблона, который фиксирует за вас типовые инженерные решения: структуру каталогов, build-файл, базовый класс приложения, минимальные зависимости и тестовый скелет. Это как набор «заводских настроек» для нового телефона: вы всё равно потом настроите его под себя, но стартовать с адекватной базы гораздо приятнее, чем с голого пластика.
Идея контейнера, component scanning и wiring уже понятна. Теперь всему этому нужен реальный дом — проект, который стартует без ручной сборки мира. Поэтому начинать приходится не с контроллера, а с правильного каркаса.
Важно уловить главное: в Boot-проекте всё начинается не с написания кода, а с выбора нескольких параметров. Они влияют на структуру проекта, на то, как Spring будет сканировать пакеты, как будет называться артефакт сборки и какую версию Java будет ожидать проект. Именно этим мы сейчас и займёмся.
2. Поля Initializr, которые важны
Когда вы открываете Spring Initializr, форма выглядит так, будто вас собираются принять на работу в NASA: много полей, списков, версий и загадочных слов. Хорошая новость: на старте нам нужно совсем немного. Остальное либо можно оставить по умолчанию, либо трогать позже, когда появится реальная причина, а не тревога уровня «вдруг пригодится».
Наша цель — получить проект catalog-service, который соответствует baseline курса: Java + Gradle + executable jar + Spring Boot 4.0.3, и при этом имеет нормальные имена, которые не стыдно видеть в логах, пакетах и файлах.
Ниже — практичная таблица: что означает каждое поле и что мы выбираем. Воспринимайте её как шпаргалку, чтобы не зависнуть на форме на 40 минут.
| Поле в Initializr | Что это значит по-человечески | Что ставим для курса | Почему так |
|---|---|---|---|
| Project | Какой build tool будет управлять сборкой | Gradle | Курс строится вокруг Gradle; единый стиль снижает хаос |
| Language | На каком языке будут исходники | Java | Без сюрпризов и лишнего усложнения |
| Spring Boot | Версия Boot, под которую генерируем проект | 4.0.3 | Это фиксированный baseline курса |
| Group | «Корневое пространство имён» и основа для базового Java-пакета | com.example | Классический нейтральный пример; важно понять принцип |
| Artifact | Короткое имя проекта и будущего артефакта сборки | catalog-service | Предметное имя под домен курса: сервис каталога |
| Name | Человекочитаемое имя проекта (часто = artifact) | catalog-service | Можно оставить как artifact, чтобы не плодить лишние варианты |
| Description | Текстовое описание (влияние минимальное) | что угодно короткое | Главное — не превращать это в «эссе о смысле жизни» |
| Package name | Базовый Java-пакет (можно руками) | com.example.catalogservice | Логично следует из group и artifact и хорошо читается |
| Packaging | Формат упаковки приложения | Jar | Boot-сервис обычно живёт как исполняемый jar без внешнего сервера |
| Java | Целевая версия Java проекта | 25 | Стабильный baseline курса и предсказуемость окружений |
Здесь полезно держаться одной линии: Java 25 выбираем в Initializr и ту же версию потом закрепляем в сборке. Тогда IDE, Gradle и сам проект не будут спорить друг с другом о том, на какой JDK они живут.
3. group и artifact как основа пакетов
На словах group и artifact звучат как «какие-то метаданные для сборки», поэтому новичок легко думает: «Да какая разница, напишу test и поехали». Но разница есть, и она вполне практичная. Эти два поля влияют не только на то, как проект будет называться на диске, но и на то, как будут выглядеть ваши пакеты, а значит — как Spring будет искать ваши классы.
Spring Boot по умолчанию сканирует компоненты, начиная с пакета, где лежит главный класс приложения. Поэтому базовый пакет должен быть таким, чтобы в него естественно укладывался весь проект. Если случайно выбрать странный пакет или положить главный класс не туда, получится очень «весёлая» ситуация: классы вроде бы есть, аннотации вроде бы стоят, а Spring их «не видит».
Давайте посмотрим на примере:
# То, что вы вводите в форме Initializr:
group: com.example
artifact: catalog-service
# То, что получится на выходе:
→ базовый пакет: com.example.catalogservice
→ имя проекта: catalog-service
Почему catalogservice, а не catalog-service? Потому что в Java-пакетах нельзя использовать дефис. Initializr обычно «нормализует» имя, убирая дефисы.
Вот минимальная иллюстрация: строка package сверху файла берётся именно из выбранной пакетной базы.
package com.example.catalogservice;
/**
* Здесь нам важен базовый пакет.
* Сам класс пока пустой — структура проекта растёт именно от package,
* а не от содержимого этого файла.
*/
public class CatalogServiceApplication {
// Пока без логики.
}
Пока это просто пустой класс, и это нормально. Но именно из строки package ... дальше вырастет вся структура проекта.
Чтобы увидеть связь совсем явно, держите в голове простую схему:
flowchart TD
%% group и artifact — это входные параметры (метаданные), которые задают «географию» проекта
A["group: com.example"] --> C["base package: com.example.catalogservice"]
B["artifact: catalog-service"] --> C
%% Главный класс должен лежать в базовом пакете: от него стартует сканирование компонентов
C --> D["CatalogServiceApplication в base package"]
%% Дальше Spring «видит» все подпакеты (и компоненты внутри них), если они лежат ниже по дереву
D --> E["component scan видит подпакеты: config, catalog, ..."]
Здесь не нужно пугаться слова scan: это всего лишь «Spring пробегается по пакетам и ищет классы, отмеченные как компоненты». А вы, выбирая group и artifact, по сути задаёте стартовую географию этого «пробега».
Ещё один практичный нюанс: artifact влияет на то, как будет называться ваш артефакт сборки. Когда вы будете собирать проект, итоговый jar часто получает имя вроде catalog-service-0.0.1-SNAPSHOT.jar. Это не главная тема сегодняшней лекции, но это ещё один повод выбрать короткое и понятное имя — чтобы потом не запускать файл с названием на три экрана.
4. Практические настройки проекта
Packaging: Jar и War
Слово packaging в Initializr звучит так, будто сейчас начнётся лекция по архиваторам. На деле всё проще: вы выбираете, в каком формате приложение будет собираться и запускаться. Для Spring Boot сегодня самый естественный путь — Jar, потому что Boot-приложение обычно живёт как самодостаточный сервис: запускается одной командой и поднимает встроенный сервер (embedded) внутри себя.
Формат War — это более старый (и всё ещё встречающийся) подход, когда приложение собирают как web archive, а затем деплоят во внешний сервер приложений. Для учебного курса по Boot это почти всегда лишняя ветка сложности: появляется внешний контейнер, появляются вопросы «куда деплоить», «какой сервер», «какая конфигурация» — и вы теряете ощущение, что приложение запускается как обычная программа.
Поэтому в этом курсе мы фиксируем простую и очень практичную идею: catalog-service должен быть исполняемым jar, который запускается как обычное приложение. Это хорошо укладывается в философию Boot: минимальный порог входа, одинаковое поведение в IDE и вне IDE и понятная модель «один сервис — один процесс».
Команды пока не важны: сначала нужно зафиксировать саму форму проекта. Здесь достаточно запомнить выбор: Packaging = Jar. Это решение не случайное, а методически полезное.
Версия Java в Initializr
Версия Java в форме Initializr выглядит как пункт из выпадающего списка, но последствия у неё очень реальные. Если выбрана одна версия, а реально проект собирается и запускается на другой, вы можете получить ошибки, которые новичку кажутся «рандомными». Например, IDE подчёркивает код красным, Gradle ругается на несовместимость, а приложение не стартует, хотя вы ничего «странного» не делали.
В нашем курсе мы выбираем Java 25 как целевую версию проекта. Это удобно не потому, что «цифра красивая», а потому, что проекту нужен один понятный baseline без разъехавшихся окружений.
Ещё один момент, который полезно понимать новичку: «версия Java» — это не только про то, какая JVM стоит на машине. Это ещё и то, какой bytecode будет генерироваться, какие API доступны и чего ожидает сборка. Выбор в Initializr — первый шаг к тому, чтобы эта версия стала частью проекта, а не «настроением вашей машины».
Если на машине несколько JDK, это само по себе не проблема. Проблема начинается, когда Initializr, IDE и сборка смотрят на разные версии. Тогда вы ловите ошибки, которые выглядят как «всё сломалось, хотя я ничего не менял».
Сегодня мы ограничимся простым правилом: выбрали Java 25 в Initializr — и дальше держимся этой линии, чтобы не устраивать себе сборочную лотерею.
Минимальная проверка после Generate
После того как вы выбрали параметры и нажали Generate, вы скачаете zip-архив. В этот момент у новичка часто возникает чувство: «Ну, архив скачался… а дальше что?» Дальше — небольшая проверка: важно убедиться, что каркас получился ровно в той форме, которую вы задали в Initializr. Полной экскурсии по дереву проекта здесь не нужно — пока достаточно опорных точек.
Пока достаточно проверить четыре вещи. Во‑первых, в src/main/java появился базовый пакет com/example/catalogservice. Во‑вторых, внутри него лежит главный класс приложения. Если в нём уже есть @SpringBootApplication и main(), всё в порядке: Boot entry point на месте. В‑третьих, в корне проекта есть build.gradle.kts, settings.gradle.kts, gradlew и папка src. В‑четвёртых, package name главного класса совпадает с той базой, которую вы собрали из group/artifact.
Этого пока достаточно. Нам не нужен глубокий разбор всей структуры проекта; важно лишь увидеть, что генерация не уехала в сторону и catalog-service стартует с ожидаемого каркаса.
5. Зависимости в Initializr
Самая коварная часть формы Initializr — список зависимостей. Там столько красивых слов, что хочется поставить галочки везде, будто вы набираете себе «скиллы» в RPG: «Web», «Security», «Data», «Cloud», «GraphQL»… Потом проект генерируется, и вы удивляетесь, почему он стартует 40 секунд, в логах тысяча строк, а вы пока хотели просто «Hello, world».
На старте важно придерживаться взрослого, скучного, но очень рабочего принципа: добавляем только то, что нужно для текущей учебной задачи. В нашем случае задача простая — создать каркас catalog-service, который уже является Boot-приложением и в будущем станет web-сервисом.
Поэтому в Initializr мы выбираем минимальный, понятный набор. Для курса разумно добавить зависимость для web-слоя. В форме Initializr она может называться просто Spring Web, а в build.gradle.kts у нас должна появиться точная зависимость org.springframework.boot:spring-boot-starter-webmvc. Это не значит, что нам уже сейчас нужен контроллер или подробный разбор HTTP. Пока достаточно того, что каркас проекта соответствует своей роли: это web-сервис, а не консольная программа, которая потом внезапно «перепрыгнет» в веб.
При этом важно сознательно не брать на старте всё подряд. Например, подключать Security «на всякий случай» — плохая идея: это отдельная дисциплина, и она заметно меняет поведение приложения. Аналогично не стоит хватать JPA и базу данных, потому что у нас проект по плану read-only и без БД. Даже если вы в будущем будете работать с данными, для этого есть отдельный курс, и мы туда сегодня не сворачиваем.
Ещё одна типичная «галочка-ловушка» — Lombok. Lombok может быть удобным, но для новичка он часто превращается в скрытую магию: вы не видите явного конструктора, не понимаете, откуда появились методы и в какой момент компилятор «подменил» вам класс. В этом курсе нам важно, чтобы код был максимально прозрачным. Так что если рука тянется поставить Lombok — это нормальный рефлекс, но мы его аккуратно придержим.
В итоге правильная психология такая: Initializr — это не меню ресторана, где нужно «попробовать всё», а касса в аэропорту: берём только то, что нужно для полёта, а чемоданы с лишними вещами оставляем дома.
6. Типичные ошибки при выборе параметров в Spring Initializr
Ошибка №1: случайный group вроде test, myapp или java.
Соблазн понятный: хочется быстрее перейти к коду. Но group влияет на базовый пакет, а пакет — на то, как Spring будет искать ваши компоненты. Случайный group потом начинает выглядеть странно в каждом файле (package test.catalogservice;), и в какой-то момент вы захотите всё переименовать. Лучше сразу выбрать нормальную, нейтральную схему вроде com.example и держаться её в рамках курса.
Ошибка №2: слишком длинный или «креативный» artifact.
artifact влияет на имя проекта, артефакта сборки и часто на массу автоматических мест (папки, настройки IDE, команды). Если вы назвали проект super-mega-ultra-catalog-service-for-my-future-startup, вы будете печатать это руками в неожиданных местах и проклинать себя на каждом шаге. Хороший artifact — короткий, предметный, без лишних слов: catalog-service как раз из этой категории.
Ошибка №3: выбрать Packaging = War, потому что «я где-то видел, что так бывает».
WAR — это отдельная модель деплоя во внешний сервер приложений. Для учебного Boot-проекта это чаще всего означает лишнюю сложность и путаницу «почему оно запускается не так». В рамках курса нам нужен самодостаточный сервис, поэтому Jar — правильный и простой выбор.
Ошибка №4: выбрать версию Java «какую угодно», а потом удивляться конфликтам окружения.
Если вы поставили в Initializr одну версию, а IDE/сборка живут в другой, вы ловите ошибки, которые выглядят как «всё сломалось, хотя я ничего не менял». В учебном проекте лучше держаться выбранного baseline (у нас это Java 25) и не менять версию без осознанной причины.
Ошибка №5: поставить слишком много зависимостей «на будущее».
Когда вы выбираете сразу web, security, data, cloud и ещё пять стартеров, проект превращается в тяжёлый комбайн, который ведёт себя «не так», как вы ожидаете. На старте мы берём минимально нужное для каркаса (в нашем случае — web-зависимость под будущий сервис) и не пытаемся решить задачи, которых ещё нет. Это экономит и время, и нервы, и качество понимания.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ