Конфигурация на Java
Java-конфигурация появилась начиная с Spring 3 и стала основным подходом к конфигурированию с Spring 5+. Суть – вы заводите один или несколько классов, которые сами создают бины. Такой класс отмечается аннотацией @Configuration, что указывает Spring, что в нем содержатся определения бинов. Внутри методы с аннотацией @Bean возвращают экземпляры необходимых классов. Например:
@Configuration
public class AppConfig {
@Bean // Определение бина Service
public Service service() {
// Внедрение зависимости repository через вызов метода repository()
return new Service(repository());
}
@Bean // Определение бина Repository
public Repository repository() {
return new Repository();
}
}
Этот класс AppConfig при запуске Spring-приложения будет прочитан IoC-контейнером. Он увидит два бина: service и repository. Порядок создания и связывания аналогичен примеру с XML: сначала вызовется repository() (чтобы получить объект Repository), затем service(), внутри которого Spring заметит, что требуется Repository – и подставит уже созданный экземпляр (или создаст по необходимости). Бины по умолчанию singleton scope, поэтому при повторных вызовах метода repository() Spring будет возвращать один и тот же объект, кэшируя результат.
Преимущества Java-конфигурации: во-первых, она типизирована – если вы опечатаетесь в имени класса или метода, это обнаружится еще на этапе компиляции. Во-вторых, IDE может помогать навигацией и автодополнением. В-третьих, вы можете использовать всю силу Java: условия, циклы, вычисления – например, выбрать реализацию бина в зависимости от параметров системы:
@Bean
public DataSource dataSource() {
if (Environment.isProduction()) {
return new HikariCPDataSource(prodSettings);
} else {
return new H2Database().getDataSource();
}
}
В-четвертых, конфигурация – это тоже класс, ее можно разбивать на несколько классов (по модулям приложения), наследовать, komponовать. Spring позволяет импортировать одну конфигурацию в другую (@Import), что делает конфигурирование крупного приложения более модульным.
В контексте Spring Boot, большая часть автоконфигурации выполнена также с помощью классов @Configuration и бинов – просто эти классы находятся внутри Spring Boot библиотек и активируются, когда в класспассе обнаружена та или иная технология. Например, если у вас зависимость spring-boot-starter-web, то при запуске автоматически подтянется конфигурация, которая создает бин типа DispatcherServlet для MVC, бины view-резолверов и пр. Обычно разработчику не нужно писать много своих @Configuration классов в Spring Boot приложении – достаточно одного класса с @SpringBootApplication (который сам является комбинацией @Configuration, @ComponentScan и нескольких других аннотаций). Тем не менее, понимание Java-конфигурации важно: если требуются нестандартные настройки, вы всегда можете добавить свои классы конфигурации с определениями бинов.
Конфигурация через аннотации и сканирование
Самый «магический» и минималистичный способ – вообще не писать отдельные конфигурационные классы, а пометить сами классы предметной области специальными аннотациями, и позволить Spring их автоматически зарегистрировать. Эти аннотации называют стереотипами: @Component (универсальная), а также ее специализированные варианты: @Service (для сервис-слоя), @Repository (для классов доступа к БД), @Controller (для MVC-контроллеров) и @RestController. Все они по сути делают одно и то же – отмечают класс как кандидата на создание бина. Например:
@Component
public class EmailSender implements MessageSender { ... }
@Service
public class NotificationService {
@Autowired
private MessageSender messageSender;
...
}
В данном примере класс EmailSender помечен компонентом, а NotificationService помечен как сервис и имеет зависимость от MessageSender. При сканировании Spring найдет EmailSender, создаст бин с именем emailSender, найдет NotificationService, создаст бин notificationService. У последнего через @Autowired поле messageSender будет заполнено ссылкой на бин EmailSender (так как он реализует требуемый интерфейс MessageSender).
Чтобы это заработало, нужно включить сканирование вашего пакета. В чистом Spring для этого в XML конфигурации используется <context:component-scan base-package="com.example.app"/> или в Java-конфигурации – аннотация @ComponentScan("com.example.app"). В Spring Boot упрощено: аннотация @SpringBootApplication сама включает компонент-сканирование для пакета, в котором находится класс с main (и всех подпакетов). Таким образом, в типичном Spring Boot проекте достаточно правильно разнести классы по пакетам, и все нужные бины будут зарегистрированы автоматически.
Аннотационный способ резко снижает объем конфигурационного кода. Добавил новую службу – просто повесил @Service, и она подхватится контейнером. Но нужно соблюдать договоренности: например, если есть несколько реализаций одного интерфейса, @Autowired без указания по имени может запутаться – тогда используют @Qualifier или назначают одну из реализаций @Primary. Тонкости конфигурации все равно могут потребовать дополнительного кода, но общая тенденция такова, что современные Spring-приложения минимально конфигурируются вручную. Разработчик описывает компоненты аннотациями, а фреймворк сам выстраивает граф зависимостей.
Стоит отметить, что Spring Boot также позволяет внешнюю конфигурацию через файлы application.properties или application.yml – однако они служат для настроек параметров (порт сервера, строки подключения и т.д.), а не для определения бинов. Бины же в 2025 году практически всегда определяются либо аннотациями, либо Java-коном (в редких случаях XML). Все три подхода при желании можно смешивать. Например, можно завести основной контекст на аннотациях, а какой-то специфичный модуль подключить через импорт XML. Spring IoC контейнер универсален и считывает метаданные конфигурации из разных источников: хоть XML, хоть классы, хоть аннотации – преобразуя их во внутренние описания BeanDefinition (которые содержат информацию о классе бина, его зависимостях, методах init/destroy, scope и т.п.).
Современные рекомендации (2025): используйте аннотации и Java-конфигурацию, так как они лучше поддерживаются и понятнее в больших проектах. XML-конфигурацию применять лишь при необходимости интеграции со старым кодом или библиотеками, требующими XML. Всегда по возможности предпочитайте конвенцию (то есть соглашения о наименованиях, пакетах, аннотациях) вместо разрастания явных конфигураций. Spring Boot уже предоставляет оптимальные настройки по умолчанию для большинства случаев, поэтому часто вообще не нужно писать свою конфигурацию для стартовых подключений (например, DataSource для БД или DispatcherServlet для веб – они настроятся автоматикой). Если же требуется явная настройка, Java-класс с @Bean методами будет лучшим выбором, поскольку в нем можно использовать привычный Java-код и логику.
Контейнер ApplicationContext
ApplicationContext – центральный интерфейс контейнера Spring IoC, расширяющий функциональность BeanFactory. В контексте Spring термины IoC-контейнер и ApplicationContext зачастую синонимичны, так как именно через реализацию ApplicationContext работают приложения.
Возможности ApplicationContext: он не только загружает определения бинов и управляет их созданием/внедрением, но и автоматически обрабатывает связанные инфраструктурные бины. Например, ApplicationContext сам регистрирует BeanPostProcessor и BeanFactoryPostProcessor бины (если найдет таковые в конфигурации), что позволяет поддерживать аннотации типа @Autowired, АОП-прокси и др. Кроме того, контекст обеспечивает:
публикацию событий и работу с слушателями (механизм ApplicationEvent),
международную поддержку сообщений (интерфейс MessageSource для i18n),
механизм хранения средовых переменных (Environment) и доступа к ресурсам (ResourceLoader).