Создание десктопного (консольного или Swing) приложения на Spring Boot

Создадим минимальное Spring Boot приложение, которое будет выполняться на рабочем столе пользователя, используя при этом все возможности фреймворка.

Перейдите на сайт https://start.spring.io и создайте Spring Boot приложение, выбрав подходящие вам параметры слева или оставьте то, что выбрано по умолчанию.

Для запуска десктопного приложения никаких стартеров не требуется. Поэтому нет необходимости нажимать справа кнопку ADD DEPENDENCIES… и что-либо добавлять. Поэтому здесь тоже либо оставляем пустым как есть, либо добавляем по своему вкусу.

Нажимаем кнопку GENERATE:

Распакуйте скачанный архив и откройте его в среде разработки.

Зависимости

Настройки сборщиков (Maven или Gradle) будут храниться в соответствующих папках/файлах. Рассмотрим эти настройки, build.gradle либо pom.xml, смотря какой сборщик выбрали.

Если не были выбраны никакие зависимости, то инициализатор Spring’а добавит в проект spring-boot-starter.

В Gradle:

В Maven:

Наличие этого стартера приведёт к загрузке базовый зависимостей, необходимых для работы Spring приложения:

Аннотация @SpringBootApplication

Инициализатор также создаст главный класс приложения следующего содержания (имя класса может быть другим, зависит от выбранных настроек):

Главный класс приложения помечается аннотацией @SpringBootApplication, которая заменяет собой три другие аннотации (можно написать и их, но @SpringBootApplication короче):

  • @EnableAutoConfiguration позволяет Spring’у проанализировать зависимости и создать конфигурации по умолчанию для тех служебных бинов, для которых это возможно.
  • @ComponentScan указывает Spring’у искать компоненты, из которых нужно сделать бины и положить их в контекст, в текущем пакете и всех подпакетах.
  • @Configuration позволяет в этом классе создавать методы, помеченные аннотацией @Bean, возвращаемые объекты которых становятся бинами и помещаются в контекст.

Метод SpringApplication.run(..)

Метод SpringApplication.run(..)

  • создаст контекст Spring приложения;
  • преобразует параметры командной строки, если они переданы, в настройки (properties) приложения;
  • создаст и поместит все бины-синглтоны в контекст;
  • запустит методы run() бинов ApplicationRunner и CommandLineRunner.

Обычно при создании и эксплуатации десктопного приложения мы не передаём никакие параметры в командную строку и не используем Раннеры. Поэтому при разработке такого приложения нас интересует, что после выполнения метода SpringApplication.run(..) у нас создан контекст и инициализированы все бины.

Таким образом сразу после метода SpringApplication.run(..) можно помещать свой код приложения.

Доступ к контексту приложения

Модифицируем главный класс приложения следующим образом:

Обратим внимание, что кроме всего прочего метод SpringApplication.run(..) возвращает ссылку на созданный контекст приложения. По этой ссылке можно вручную добавлять бины в контекст и извлекать из него.

Конечно, мы создаём Spring приложение прежде всего для того, чтобы пользоваться автоматическим внедрением зависимостей. Тем не менее в десктопных приложениях это не всегда возможно, поэтому иногда с контекстом приходится взаимодействовать вручную. Поэтому полезно знать, что метод SpringApplication.run(..) возвращает ссылку на контекст, которую можно сохранить и в дальнейшем использовать при необходимости.

Строка System.out.println("Привет, мир!"); является началом произвольного кода приложения. После того как она выполнится приложение закончит свою работу.

Мы можем создавать любые бины с помощью аннотаций @Configuration + @Bean или @ComponentScan + @Component/@Service/@Repository и они при запуске приложения будут добавлены в контекст, где будут инъектированы друг другу в качестве зависимостей.

Первый такой бин скорее всего придётся извлечь из контекста руками. Давайте посмотрим, как это сделать.

Извлечение зависимости из контекста

Создадим бин и поместим его в тот же пакет, где лежит главный класс приложения, либо в один из подпакетов этого пакета:

Модифицируем главный класс приложения следующим образом:

С помощью метода SpringApplication.run(..) мы не только инициализируем контекст и бины Spring приложения, но и получаем ссылку на этот контекст. Затем из контекста с помощью метода getBean(..) мы извлекаем нужный нам бин, передав в него класс требуемого бина. Получив бин, мы можем вызывать его методы.

В принципе на этом создание базового консольного приложения закончено. Можно добавить Swing компоненты.

Создание графического Swing приложения

Добавим к имеющимся классам класс Swing компонента. Для простоты демонстрации это будет JFrame, которая отобразит главное окно приложения:

Мы помечаем компонент JFrame аннотацией @Component, так как хотим, чтобы Spring определил его как бин и добавил в контекст. Кроме того мы создаём поле CustomBean myBean и конструктор вида public MainFrame(CustomBean customBean), так как хотим, чтобы Spring к тому же внедрил в этот компонент зависимость.

Если Spring сможет создать из этого класса бин и внедрить зависимость, то в окне приложения мы ожидаем увидеть ярлык JLabel с надписью «some data», которая будет взята из внедрённого компонента CustomBean.

Исправим главный класс приложения следующим образом:

Мы должны передать в приложение параметр headless равный false, иначе приложение не поднимется, упадёт с ошибкой java.awt.HeadlessException.

В данном примере мы воспользовались методом System.setProperty(..). Но есть и другие способы: передать через аргумент командной строки или воспользоваться классом SpringApplicationBuilder.

Кроме того, обратите внимание, что мы, запуская Swing компоненты, достаём mainFrame из контекста. Часто разработчику не удаётся поженить Swing и Spring просто потому, что вместо внедрения зависимостей и обращения к контексту, разработчик по привычке использует оператор new.

Запустив приложение, мы должны получить такое окно:

Заключение

Для проверки тех или иных возможностей Spring’а, не связанных с обработкой web-запросов, консольное приложение — отличный вариант. Как правило такие приложения поднимаются и работаю очень быстро, что делает их очень удобными для тестирования фич.

Что касается Swing приложений на фреймворке Spring, то в случае необходимости напилить кастомный ипотечный калькулятор или какой-то другой велосипед на Swing’е возможность добавить Spring с его стартерами вроде Spring Data Jpa значительно ускоряет и упрощает разработку.