200 вопросов по Spring
200 вопросов по Spring
Основы Spring Framework
Вопрос
Что такое Spring Framework?
Ответ
Spring Framework — это открытая платформа для разработки корпоративных Java-приложений. Она предоставляет комплексную инфраструктуру для управления зависимостями, конфигурацией, транзакциями, безопасностью, доступом к данным и другими аспектами enterprise-разработки. Основной принцип — инверсия управления (IoC) и внедрение зависимостей (DI).
Вопрос
Какие основные модули входят в Spring Framework?
Ответ
Основные модули Spring Framework включают:
- Core Container (Beans, Context, Expression Language)
- Data Access/Integration (JDBC, ORM, OXM, JMS, Transactions)
- Web (Web, Web MVC, Web Socket, Web Reactive)
- AOP (Aspect-Oriented Programming)
- Instrumentation
- Messaging
- Test
Вопрос
Что такое Inversion of Control (IoC)?
Ответ
Inversion of Control — это принцип проектирования, при котором управление созданием и связыванием объектов передаётся внешнему контейнеру, а не остаётся в руках самого приложения. Это позволяет уменьшить связанность компонентов и упростить тестирование и поддержку.
Вопрос
Что такое Dependency Injection (DI)?
Ответ
Dependency Injection — это реализация IoC, при которой зависимости объекта предоставляются ему извне, обычно через конструктор, сеттер или интерфейс. Это позволяет объекту не заботиться о создании своих зависимостей, делая его более гибким и тестируемым.
Вопрос
Как Spring реализует IoC?
Ответ
Spring реализует IoC через контейнер BeanFactory и его расширение ApplicationContext. Контейнер управляет жизненным циклом бинов, их конфигурацией и внедрением зависимостей на основе метаданных (XML, аннотации или Java-конфигурации).
Вопрос
В чём разница между BeanFactory и ApplicationContext?
Ответ
BeanFactory — базовый контейнер IoC, предоставляющий базовые функции управления бинами. ApplicationContext — его подкласс, добавляющий поддержку:
- i18n (интернационализации)
- публикации событий
- декларативной загрузки файлов ресурсов
- интеграции с AOP
- автоматической регистрации бинов PostProcessor'ов
ApplicationContext предпочтителен в большинстве приложений.
Вопрос
Что такое Spring Bean?
Ответ
Spring Bean — это объект, управляемый контейнером Spring. Он создаётся, конфигурируется и управляется контейнером на основе определения (через XML, аннотации или Java-конфигурацию). Жизненный цикл бина контролируется Spring.
Вопрос
Как определить бин в Spring?
Ответ
Бин можно определить несколькими способами:
- С помощью аннотации
@Component(или её производных:@Service,@Repository,@Controller) - С помощью метода с аннотацией
@Beanвнутри класса с@Configuration - Через XML-конфигурацию с тегом
<bean>
Пример:
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
}
Вопрос
Какие способы конфигурации Spring существуют?
Ответ
Существуют три основных способа конфигурации Spring:
- XML-конфигурация
- Аннотации (
@Component,@Autowired,@Configuration,@Beanи др.) - Java-based конфигурация (через классы с
@Configuration)
Современные приложения преимущественно используют аннотации и Java-конфигурацию.
Вопрос
Что делает аннотация @Component?
Ответ
Аннотация @Component указывает, что класс является кандидатом на управление Spring-контейнером как бин. При включённом компонентном сканировании (@ComponentScan) Spring автоматически обнаруживает такие классы и регистрирует их как бины.
Вопрос
Что такое @ComponentScan?
Ответ
@ComponentScan — аннотация, которая указывает Spring искать классы с аннотациями @Component, @Service, @Repository, @Controller в указанном пакете (или пакетах) и регистрировать их как бины в контексте приложения.
Вопрос
Какие стереотипные аннотации есть в Spring?
Ответ
Стереотипные аннотации — это специализированные формы @Component:
@Service— для сервисного слоя@Repository— для слоя доступа к данным@Controller— для веб-контроллеров в Spring MVC@RestController— комбинация@Controllerи@ResponseBodyдля REST API
Они семантически обогащают код, но технически ведут себя как @Component.
Вопрос
Что делает аннотация @Autowired?
Ответ
@Autowired указывает Spring автоматически внедрить зависимость в поле, конструктор или метод. По умолчанию внедрение происходит по типу (by type). Если найдено несколько подходящих бинов, используется дополнительная квалификация (например, @Qualifier).
Вопрос
Можно ли использовать @Autowired с конструктором?
Ответ
Да. Использование @Autowired с конструктором — рекомендуемый способ внедрения зависимостей, так как он обеспечивает неизменяемость и гарантирует, что зависимости не будут null при создании объекта. Начиная с Spring 4.3, если у класса только один конструктор, аннотация @Autowired может быть опущена.
Вопрос
Что такое @Qualifier?
Ответ
@Qualifier используется вместе с @Autowired, чтобы указать, какой именно бин нужно внедрить, если существует несколько бинов одного типа. Он работает по имени бина или по пользовательской квалификационной аннотации.
Пример:
@Autowired
@Qualifier("emailService")
private NotificationService service;
Вопрос
Что такое жизненный цикл Spring Bean?
Ответ
Жизненный цикл Spring Bean включает этапы:
- Создание экземпляра (через конструктор или фабричный метод)
- Внедрение зависимостей
- Вызов методов, помеченных
@PostConstruct - Использование бина
- Вызов методов, помеченных
@PreDestroy - Уничтожение бина
Spring также поддерживает callback-интерфейсы InitializingBean и DisposableBean.
Вопрос
Как задать метод инициализации и уничтожения бина?
Ответ
Методы инициализации и уничтожения можно задать:
- Через аннотации
@PostConstructи@PreDestroy - Через атрибуты
initMethodиdestroyMethodв@Bean - Через реализацию интерфейсов
InitializingBeanиDisposableBean - Через атрибуты
init-methodиdestroy-methodв XML
Пример:
@Bean(initMethod = "init", destroyMethod = "cleanup")
public MyBean myBean() {
return new MyBean();
}
Вопрос
Что такое scope бина? Какие scope поддерживаются в Spring?
Ответ
Scope определяет жизненный цикл и количество экземпляров бина. Поддерживаемые scope:
singleton— один экземпляр на контекст (по умолчанию)prototype— новый экземпляр при каждом запросеrequest— один экземпляр на HTTP-запрос (только в веб-контексте)session— один экземпляр на HTTP-сессиюapplication— один экземпляр на ServletContextwebsocket— один экземпляр на WebSocket-сессию
Вопрос
Что происходит при использовании prototype scope?
Ответ
При prototype scope контейнер создаёт новый экземпляр бина при каждом запросе. Однако контейнер не управляет жизненным циклом таких бинов после их создания — вызовы @PreDestroy и других методов уничтожения не гарантируются.
Вопрос
Как внедрить свойство из файла конфигурации?
Ответ
Свойства из application.properties или application.yml можно внедрить с помощью аннотации @Value.
Пример:
app.name=MyApp
@Value("${app.name}")
private String appName;
Вопрос
Что такое @ConfigurationProperties?
Ответ
@ConfigurationProperties — аннотация для группового связывания внешних свойств с полями Java-объекта. Она удобна для работы с большим количеством связанных параметров.
Пример:
@ConfigurationProperties(prefix = "database")
@Component
public class DatabaseProperties {
private String url;
private String username;
// геттеры и сеттеры
}
Требует @EnableConfigurationProperties или автоматической регистрации через @Component.
Вопрос
Что делает @SpringBootApplication?
Ответ
@SpringBootApplication — это составная аннотация, эквивалентная трём:
@Configuration— помечает класс как источник конфигурации@EnableAutoConfiguration— включает автоматическую конфигурацию Spring Boot@ComponentScan— включает сканирование компонентов в текущем пакете и подпакетах
Это основная аннотация для запуска Spring Boot-приложения.
Вопрос
Что такое Spring Boot?
Ответ
Spring Boot — это надстройка над Spring Framework, предназначенная для упрощения создания standalone-приложений с минимальной конфигурацией. Она предоставляет:
- Автоматическую конфигурацию
- Встроенные серверы (Tomcat, Jetty и др.)
- Стартеры (starter dependencies)
- Actuator для мониторинга
- Упрощённое развёртывание
Вопрос
Что такое starter-зависимости в Spring Boot?
Ответ
Starter-зависимости — это предопределённые наборы зависимостей для распространённых сценариев (веб, данные, безопасность и т.д.). Например, spring-boot-starter-web включает всё необходимое для создания веб-приложения: Spring MVC, Tomcat, Jackson и другие.
Вопрос
Как изменить порт веб-сервера в Spring Boot?
Ответ
Порт можно изменить в файле application.properties:
server.port=8081
Или в application.yml:
server:
port: 8081
Вопрос
Что такое условная конфигурация в Spring Boot?
Ответ
Условная конфигурация позволяет регистрировать бины или конфигурационные классы только при выполнении определённых условий. Для этого используются аннотации:
@ConditionalOnProperty@ConditionalOnClass@ConditionalOnMissingBean@ConditionalOnWebApplication
и другие из пакетаorg.springframework.boot.autoconfigure.condition.
Вопрос
Что такое Spring Profiles?
Ответ
Profiles позволяют определять разные конфигурации для разных окружений (dev, test, prod). Бины или конфигурации активируются только при активном профиле.
Пример:
@Profile("dev")
@Configuration
public class DevConfig { ... }
Активация: spring.profiles.active=dev в application.properties.
Вопрос
Как активировать профиль в Spring Boot?
Ответ
Профиль можно активировать:
- В
application.properties:spring.profiles.active=prod - Через переменную окружения:
SPRING_PROFILES_ACTIVE=prod - Через аргумент JVM:
-Dspring.profiles.active=prod - Программно:
SpringApplication.setAdditionalProfiles("test")
Вопрос
Что такое ApplicationContext?
Ответ
ApplicationContext — это центральный интерфейс Spring для доступа к контейнеру IoC. Он предоставляет методы для получения бинов, публикации событий, доступа к ресурсам и другим функциям. Реализации включают AnnotationConfigApplicationContext, ClassPathXmlApplicationContext, WebApplicationContext.
Вопрос
Как получить бин из контекста программно?
Ответ
Можно внедрить ApplicationContext и вызвать метод getBean():
@Autowired
private ApplicationContext context;
public void someMethod() {
MyService service = context.getBean(MyService.class);
}
Вопрос
Что такое @Primary?
Ответ
Аннотация @Primary указывает, какой бин следует использовать по умолчанию при внедрении зависимости, если существует несколько кандидатов одного типа. Это помогает разрешить неоднозначность без явного указания @Qualifier.
Пример:
@Bean
@Primary
public DataSource primaryDataSource() {
return new HikariDataSource();
}
@Bean
public DataSource secondaryDataSource() {
return new DriverManagerDataSource();
}
При внедрении DataSource будет использован primaryDataSource.
Вопрос
Что такое фабричный метод в контексте Spring?
Ответ
Фабричный метод — это статический или экземплярный метод, возвращающий объект, который Spring регистрирует как бин. Такой метод помечается аннотацией @Bean внутри класса с @Configuration.
Пример:
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
}
Здесь myService() — фабричный метод.
Вопрос
Что такое FactoryBean?
Ответ
FactoryBean — это специальный интерфейс Spring (org.springframework.beans.factory.FactoryBean), позволяющий создавать сложные объекты через собственную логику инициализации. Он используется, когда стандартное создание бина недостаточно гибко (например, для прокси-объектов).
Spring вызывает метод getObject() для получения экземпляра бина, а не сам FactoryBean.
Вопрос
Как работает @Value с коллекциями?
Ответ
@Value может внедрять коллекции из свойств, используя синтаксис SpEL или разделители:
app.roles=ADMIN,USER,GUEST
@Value("#{'${app.roles}'.split(',')}")
private List<String> roles;
Или через массив:
@Value("${app.roles}")
private String[] roleArray;
Для более сложных случаев рекомендуется использовать @ConfigurationProperties.
Вопрос
Что такое Spring Expression Language (SpEL)?
Ответ
SpEL — это мощный язык выражений, встроенный в Spring, позволяющий выполнять вычисления во время выполнения: обращаться к свойствам, вызывать методы, работать с коллекциями, выполнять арифметические и логические операции.
Примеры:
@Value("#{systemProperties['user.name']}")
private String username;
@Value("#{T(java.lang.Math).random() * 100}")
private double randomValue;
Вопрос
Как внедрить ApplicationContext в компонент?
Ответ
Можно внедрить ApplicationContext напрямую через конструктор, поле или сеттер:
@Component
public class MyService {
private final ApplicationContext context;
public MyService(ApplicationContext context) {
this.context = context;
}
}
Также класс может реализовать интерфейс ApplicationContextAware, но это менее предпочтительно, чем DI.
Вопрос
Что такое @Profile и как он работает?
Ответ
@Profile ограничивает регистрацию бина или конфигурационного класса только тогда, когда активирован определённый профиль. Это позволяет настраивать разные бины для dev, test, prod и других сред.
Пример:
@Profile("dev")
@Bean
public DataSource devDataSource() {
return new EmbeddedDatabaseBuilder().build();
}
Вопрос
Как программно установить активный профиль?
Ответ
Активный профиль можно установить программно до запуска приложения:
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MyApp.class);
app.setAdditionalProfiles("prod");
app.run(args);
}
Или через SpringApplicationBuilder:
new SpringApplicationBuilder()
.profiles("test")
.sources(MyApp.class)
.run(args);
Вопрос
Что такое условная конфигурация на основе наличия класса?
Ответ
Аннотация @ConditionalOnClass регистрирует бин или конфигурацию только если указанный класс присутствует в classpath. Это часто используется в автоконфигурациях Spring Boot для подключения функциональности при наличии зависимостей (например, DataSource при наличии HikariCP).
Пример:
@Configuration
@ConditionalOnClass(name = "com.zaxxer.hikari.HikariDataSource")
public class HikariConfig { ... }
Вопрос
Что делает @ConditionalOnMissingBean?
Ответ
@ConditionalOnMissingBean регистрирует бин только если в контексте ещё не существует бина указанного типа (или с указанным именем). Это позволяет пользователям переопределять стандартные бины Spring Boot, предоставляя свои реализации.
Пример:
@Bean
@ConditionalOnMissingBean
public MyService myService() {
return new DefaultMyService();
}
Вопрос
Что такое Spring AOP?
Ответ
Spring AOP (Aspect-Oriented Programming) — это модуль, позволяющий выделять сквозную функциональность (логирование, транзакции, безопасность) в отдельные аспекты и применять их к целевым методам без изменения их кода. Spring AOP основан на прокси-паттерне и работает только с бинами Spring.
Вопрос
Какие типы советов (advice) поддерживаются в Spring AOP?
Ответ
Spring AOP поддерживает следующие типы советов:
@Before— выполняется до вызова метода@After— выполняется после завершения метода (всегда)@AfterReturning— выполняется после успешного завершения метода@AfterThrowing— выполняется при выбрасывании исключения@Around— оборачивает метод, позволяет контролировать его выполнение
Вопрос
Что такое точка среза (pointcut)?
Ответ
Точка среза — это выражение, определяющее, к каким методам применяется аспект. Она задаётся с помощью аннотации @Pointcut или непосредственно в аннотациях советов.
Пример:
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethods() {}
@Before("serviceMethods()")
public void logBefore(JoinPoint joinPoint) {
// логика
}
Вопрос
Поддерживает ли Spring AOP прокси для private-методов?
Ответ
Нет. Spring AOP основан на динамических прокси (JDK Proxy или CGLIB), которые работают только с публичными методами. Вызов private, protected или package-private методов изнутри класса не перехватывается аспектами.
Вопрос
Что такое @EnableAspectJAutoProxy?
Ответ
@EnableAspectJAutoProxy включает поддержку AOP на основе AspectJ в Spring. Эта аннотация активирует автоматическое создание прокси для бинов, содержащих аспекты. В Spring Boot она включена автоматически при наличии spring-boot-starter-aop.
Вопрос
Как Spring обрабатывает циклические зависимости?
Ответ
Spring может разрешать циклические зависимости между singleton-бинами, если хотя бы одна из зависимостей внедряется через setter или поле (а не только через конструктор). При конструкторном внедрении циклическая зависимость вызовет BeanCurrentlyInCreationException.
Spring использует «трёхуровневый кэш» для раннего доступа к частично инициализированным бинам.
Вопрос
Что такое @Lazy?
Ответ
@Lazy откладывает создание бина до первого запроса к нему, а не создаёт его при старте контекста. Это полезно для оптимизации времени запуска или разрешения циклических зависимостей.
Пример:
@Component
@Lazy
public class ExpensiveService { ... }
Также можно применять к внедрению:
@Autowired
@Lazy
private ExpensiveService service;
Вопрос
Что такое @DependsOn?
Ответ
@DependsOn указывает, что текущий бин должен быть создан после указанных бинов, даже если нет прямой зависимости. Это полезно, когда порядок инициализации важен, но связи через DI отсутствуют.
Пример:
@Bean
@DependsOn("databaseInitializer")
public MyService myService() {
return new MyService();
}
Вопрос
Что такое InitializingBean и DisposableBean?
Ответ
Это callback-интерфейсы Spring:
InitializingBeanсодержит методafterPropertiesSet(), вызываемый после внедрения всех свойств.DisposableBeanсодержит методdestroy(), вызываемый при уничтожении контекста.
Однако их использование считается устаревшим в пользу аннотаций @PostConstruct и @PreDestroy.
Вопрос
Как Spring обрабатывает свойства из нескольких источников?
Ответ
Spring Boot загружает свойства в определённом порядке приоритета (от низкого к высокому):
- Конфигурация по умолчанию
application.properties/application.ymlв classpath- Профиль-специфичные файлы (
application-dev.properties) - Свойства из папки
config/ - Аргументы командной строки (
--server.port=9090) - Переменные окружения
- Системные свойства JVM
Каждый последующий источник переопределяет предыдущий.
Spring Boot и автоконфигурация
Вопрос
Что такое Spring Boot Auto-configuration?
Ответ
Auto-configuration — это механизм Spring Boot, который автоматически настраивает бины на основе зависимостей в classpath, свойств приложения и других условий. Например, если в classpath есть HikariCP и указаны параметры подключения к БД, Spring Boot автоматически создаёт DataSource.
Auto-configuration реализуется через классы с аннотацией @Configuration и условиями вроде @ConditionalOnClass, @ConditionalOnMissingBean.
Вопрос
Как отключить определённую автоконфигурацию?
Ответ
Можно отключить автоконфигурацию с помощью аннотации @EnableAutoConfiguration(exclude = ...) или свойства spring.autoconfigure.exclude в application.properties.
Пример:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class MyApp { }
Или в application.properties:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
Вопрос
Что такое spring.factories и как он используется?
Ответ
Файл META-INF/spring.factories содержит список классов автоконфигурации, которые Spring Boot загружает при старте. Каждая строка указывает на класс с аннотацией @Configuration.
Пример содержимого:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAutoConfiguration
Начиная с Spring Boot 2.4, рекомендуется использовать META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports вместо spring.factories.
Вопрос
Как создать собственную автоконфигурацию?
Ответ
Собственная автоконфигурация — это обычный @Configuration-класс, помещённый в отдельный JAR-файл и зарегистрированный в META-INF/spring.factories (или AutoConfiguration.imports). Она должна использовать условные аннотации (@ConditionalOn...) для безопасного применения.
Пример:
@Configuration
@ConditionalOnClass(MyService.class)
@ConditionalOnMissingBean(MyService.class)
public class MyServiceAutoConfiguration {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
}
Вопрос
Что делает @SpringBootTest?
Ответ
@SpringBootTest запускает полный контекст Spring Boot для интеграционных тестов. Он загружает все бины, применяет автоконфигурацию и позволяет тестировать приложение в условиях, максимально приближённых к реальному запуску.
Можно комбинировать с @AutoConfigureTestDatabase, @MockBean, @TestPropertySource и другими аннотациями.
Вопрос
В чём разница между @WebMvcTest и @DataJpaTest?
Ответ
@WebMvcTest загружает только слой контроллеров Spring MVC, мокая сервисы и репозитории. Используется для тестирования HTTP-обработчиков.
@DataJpaTest загружает только слой доступа к данным: репозитории JPA, транзакции, встроенную БД (например, H2). Сервисы и контроллеры не загружаются.
Обе аннотации ускоряют тесты за счёт частичной загрузки контекста.
Вопрос
Как протестировать REST-контроллер без запуска сервера?
Ответ
Используйте MockMvc с аннотацией @WebMvcTest:
@WebMvcTest(MyController.class)
class MyControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private MyService service;
@Test
void testGet() throws Exception {
when(service.getMessage()).thenReturn("OK");
mockMvc.perform(get("/api"))
.andExpect(status().isOk())
.andExpect(content().string("OK"));
}
}
Вопрос
Как настроить несколько профилей одновременно?
Ответ
Можно активировать несколько профилей через запятую:
В application.properties:
spring.profiles.active=dev,local
Или через переменную окружения:
SPRING_PROFILES_ACTIVE=dev,local
Spring объединит конфигурации из всех активных профилей.
Вопрос
Как Spring Boot определяет порядок загрузки свойств?
Ответ
Spring Boot использует строгий порядок приоритета (от самого высокого к низкому):
- Аргументы командной строки (
--server.port=9090) - Переменные окружения (
SERVER_PORT=9090) - Свойства JVM (
-Dserver.port=9090) - Файлы
application-{profile}.propertiesв текущей директории - Файлы
application.propertiesв текущей директории - Файлы
application-{profile}.propertiesв classpath - Файл
application.propertiesв classpath
Последующие источники переопределяют предыдущие.
Вопрос
Что такое @ConfigurationProperties и зачем он нужен?
Ответ
@ConfigurationProperties связывает группу внешних свойств с полями Java-класса. Это удобнее, чем использовать множество @Value.
Пример:
@ConfigurationProperties(prefix = "app.email")
@Component
public class EmailProperties {
private String host;
private int port;
// геттеры/сеттеры
}
Соответствующие свойства:
app.email.host=smtp.gmail.com
app.email.port=587
Требуется @EnableConfigurationProperties или регистрация через @Component.
Spring Data и работа с базами данных
Вопрос
Что такое Spring Data?
Ответ
Spring Data — это проект Spring, упрощающий работу с хранилищами данных. Он предоставляет единый API для реляционных (JPA, JDBC), NoSQL (MongoDB, Redis) и других баз данных. Основная идея — минимизация boilerplate-кода через интерфейсы и соглашения.
Вопрос
Как работает JpaRepository?
Ответ
JpaRepository — это интерфейс Spring Data JPA, расширяющий CrudRepository и PagingAndSortingRepository. Он предоставляет готовые методы:
save(),findById(),delete()findAll(Sort),findAll(Pageable)- пакетные операции
Spring Data автоматически создаёт реализацию этого интерфейса во время выполнения.
Вопрос
Как определить собственный метод запроса в репозитории?
Ответ
Можно использовать соглашение об именовании или аннотацию @Query.
По соглашению:
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByEmail(String email);
List<User> findByAgeGreaterThan(int age);
}
С помощью JPQL:
@Query("SELECT u FROM User u WHERE u.name LIKE %:name%")
List<User> findByNameLike(@Param("name") String name);
Вопрос
Что такое @EntityScan?
Ответ
@EntityScan указывает Spring, где искать классы с аннотацией @Entity. По умолчанию Spring Boot сканирует пакет основного класса и его подпакеты. Если сущности находятся вне этой области, нужно явно указать путь:
@EntityScan("com.example.model")
@SpringBootApplication
public class MyApp { }
Вопрос
Как настроить несколько источников данных в Spring Boot?
Ответ
Нужно создать два @Configuration-класса, каждый помеченный @Primary для одного из источников. Также следует использовать @Qualifier для различения бинов.
Пример:
@Bean
@Primary
@ConfigurationProperties("app.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("app.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
Для JPA потребуется отдельные EntityManagerFactory и TransactionManager.
Вопрос
Что такое @Transactional?
Ответ
@Transactional управляет транзакциями в Spring. Метод, помеченный этой аннотацией, выполняется в рамках одной транзакции: если возникает исключение (по умолчанию — unchecked), транзакция откатывается.
Аннотация работает только при вызове через прокси (т.е. из другого бина, а не внутри того же класса).
Вопрос
Как изменить поведение отката транзакции?
Ответ
Можно указать, для каких исключений выполнять откат или не выполнять:
@Transactional(rollbackFor = CustomException.class)
public void method() { }
@Transactional(noRollbackFor = ValidationException.class)
public void method2() { }
Вопрос
Что такое Propagation.REQUIRED?
Ответ
Propagation.REQUIRED — значение по умолчанию для @Transactional. Оно означает: использовать существующую транзакцию, если она есть; иначе создать новую.
Другие варианты: REQUIRES_NEW (всегда новая), NESTED, MANDATORY, NOT_SUPPORTED, NEVER, SUPPORTS.
Вопрос
Как работает ленивая загрузка (FetchType.LAZY) в JPA?
Ответ
При FetchType.LAZY связанные сущности загружаются только при первом обращении к ним. Однако вне транзакции это вызывает LazyInitializationException, так как сессия уже закрыта.
Решения:
- Использовать
@Transactionalна уровне сервиса - Применить
JOIN FETCHв запросе - Использовать DTO и проекции
Вопрос
Что такое N+1 проблема и как её решить?
Ответ
N+1 проблема возникает, когда для получения N связанных сущностей выполняется N+1 SQL-запросов: один для основного списка и N — для каждой связанной коллекции.
Решения:
- Использовать
JOIN FETCHв JPQL - Настроить
@EntityGraph - Применить пакетную загрузку (
@BatchSize) - Использовать DTO с явным выбором полей
Spring Web и REST
Вопрос
Что делает аннотация @RestController?
Ответ
@RestController — это составная аннотация, эквивалентная @Controller + @ResponseBody. Она указывает, что все методы контроллера автоматически сериализуют возвращаемое значение в HTTP-ответ (обычно в JSON или XML), без необходимости явно указывать @ResponseBody.
Вопрос
В чём разница между @Controller и @RestController?
Ответ
@Controller используется для традиционных MVC-контроллеров, возвращающих имя шаблона (например, "home"), который затем обрабатывается ViewResolver.
@RestController предназначен для RESTful API: возвращаемые объекты сразу сериализуются в тело ответа (например, в JSON).
Вопрос
Как обработать параметры пути в REST-контроллере?
Ответ
Используется аннотация @PathVariable:
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
Можно указать имя переменной явно: @PathVariable("id").
Вопрос
Как обработать query-параметры?
Ответ
Для query-параметров используется аннотация @RequestParam:
@GetMapping("/users")
public List<User> getUsers(@RequestParam(required = false) String name,
@RequestParam(defaultValue = "0") int offset) {
return userService.findByName(name, offset);
}
Если имя параметра совпадает с именем аргумента, аннотацию можно опустить при включённом -parameters флаге компиляции.
Вопрос
Как принять JSON-тело запроса в контроллере?
Ответ
Используется аннотация @RequestBody:
@PostMapping("/users")
public User createUser(@RequestBody CreateUserRequest request) {
return userService.create(request);
}
Spring автоматически десериализует JSON в объект с помощью HttpMessageConverter (обычно Jackson).
Вопрос
Как вернуть статус 201 Created с Location заголовком?
Ответ
Можно использовать ResponseEntity:
@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody User user) {
User saved = userService.save(user);
URI location = ServletUriComponentsBuilder
.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(saved.getId())
.toUri();
return ResponseEntity.created(location).body(saved);
}
Вопрос
Что такое @Valid и как он работает?
Ответ
@Valid запускает валидацию входящего объекта на основе Bean Validation (JSR-380). Поля класса должны быть помечены ограничениями (@NotNull, @Size, @Email и др.).
Пример:
@PostMapping("/users")
public User createUser(@Valid @RequestBody CreateUserRequest request) {
return userService.create(request);
}
При нарушении правил выбрасывается MethodArgumentNotValidException.
Вопрос
Как обработать ошибки валидации?
Ответ
Создаётся глобальный обработчик исключений с @ControllerAdvice:
@ControllerAdvice
public class ValidationExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public Map<String, String> handleValidationExceptions(
MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage()));
return errors;
}
}
Вопрос
Что такое @CrossOrigin?
Ответ
@CrossOrigin включает поддержку CORS (Cross-Origin Resource Sharing) для метода или всего контроллера. Это позволяет браузеру делать запросы с другого домена.
Пример:
@CrossOrigin(origins = "https://example.com")
@GetMapping("/api/data")
public Data getData() { ... }
Можно настроить глобально через WebMvcConfigurer.
Вопрос
Как настроить глобальную обработку исключений?
Ответ
Используется класс с аннотацией @ControllerAdvice, содержащий методы с @ExceptionHandler:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(Exception ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse(ex.getMessage()));
}
}
Такой обработчик применяется ко всем контроллерам.
Безопасность и Spring Security
Вопрос
Как подключить Spring Security к Spring Boot-приложению?
Ответ
Добавляется зависимость spring-boot-starter-security. По умолчанию все HTTP-эндпоинты защищаются, создаётся пользователь user с паролем, выводимым в лог при старте.
Для настройки создаётся класс с @Configuration и @EnableWebSecurity, расширяющий WebSecurityConfigurerAdapter (до Spring Security 5.7) или использующий новый функциональный стиль.
Вопрос
Как отключить безопасность для определённых путей?
Ответ
В конфигурации безопасности:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.httpBasic(withDefaults());
return http.build();
}
Вопрос
Как настроить аутентификацию по JWT?
Ответ
Нужно реализовать:
- Фильтр для извлечения и проверки JWT из заголовка
Authorization UserDetailsServiceдля загрузки пользователяJwtUtilдля генерации и валидации токенов
Фильтр добавляется в цепочку безопасности до UsernamePasswordAuthenticationFilter.
Вопрос
Что такое UserDetailsService?
Ответ
UserDetailsService — интерфейс Spring Security для загрузки данных пользователя по имени. Его реализация должна возвращать объект UserDetails, содержащий имя, пароль, роли и флаги (аккаунт заблокирован, просрочен и т.д.).
Вопрос
Как хранить пароли безопасно?
Ответ
Пароли должны храниться в хэшированном виде с использованием алгоритмов вроде BCrypt, SCrypt или PBKDF2. В Spring Security используется PasswordEncoder.
Пример:
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
При сохранении пользователя пароль хэшируется через этот encoder.
Вопрос
Что такое CSRF и как Spring Security его обрабатывает?
Ответ
CSRF (Cross-Site Request Forgery) — атака, при которой вредоносный сайт выполняет запрос от имени авторизованного пользователя. Spring Security по умолчанию включает защиту от CSRF для всех изменяющих запросов (POST, PUT, DELETE).
Для REST API, использующих JWT, CSRF обычно отключают:
http.csrf(csrf -> csrf.disable());
Вопрос
Как получить текущего пользователя в контроллере?
Ответ
Можно использовать @AuthenticationPrincipal:
@GetMapping("/profile")
public UserProfile getProfile(@AuthenticationPrincipal UserDetails userDetails) {
return profileService.getByUsername(userDetails.getUsername());
}
Или из SecurityContext:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName();
Вопрос
Что такое OAuth2 и как его использовать в Spring?
Ответ
OAuth2 — протокол авторизации, позволяющий делегировать аутентификацию внешним провайдерам (Google, GitHub и др.). В Spring Boot используется spring-boot-starter-oauth2-client.
Конфигурация в application.yml:
spring:
security:
oauth2:
client:
registration:
google:
client-id: xxx
client-secret: yyy
Расширенные темы Spring
Вопрос
Что такое @Async и как его включить?
Ответ
@Async позволяет выполнять метод асинхронно в отдельном потоке. Для включения требуется @EnableAsync на конфигурационном классе.
Пример:
@EnableAsync
@Configuration
public class AsyncConfig {
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(5);
return executor;
}
}
@Service
public class NotificationService {
@Async
public void sendEmail(String to) {
// отправка
}
}
Вопрос
Что такое @Scheduled?
Ответ
@Scheduled выполняет метод по расписанию. Требует @EnableScheduling.
Примеры:
@Scheduled(fixedRate = 5000) // каждые 5 секунд
public void report() { }
@Scheduled(cron = "0 0 12 * * MON-FRI") // ежедневно в 12:00 по будням
public void dailyJob() { }
Вопрос
Как настроить кэширование в Spring?
Ответ
Используется аннотация @EnableCaching и аннотации на методах: @Cacheable, @CachePut, @CacheEvict.
Пример:
@Cacheable("users")
public User findById(Long id) {
return userRepository.findById(id);
}
@CacheEvict(value = "users", key = "#user.id")
public User save(User user) {
return userRepository.save(user);
}
По умолчанию используется простой in-memory кэш; можно подключить Caffeine, Redis и др.
Вопрос
Что такое @EventListener?
Ответ
@EventListener помечает метод как обработчик события Spring. События публикуются через ApplicationEventPublisher.
Пример:
@Component
public class OrderEventListener {
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
// обработка
}
}
// Публикация
@Autowired
private ApplicationEventPublisher publisher;
public void createOrder() {
// ...
publisher.publishEvent(new OrderCreatedEvent(order));
}
Вопрос
Как работает @Transactional с несколькими базами данных?
Ответ
Для каждой БД нужен свой PlatformTransactionManager. При использовании @Transactional указывается нужный менеджер через атрибут transactionManager:
@Transactional("primaryTransactionManager")
public void updatePrimaryDb() { }
@Transactional("secondaryTransactionManager")
public void updateSecondaryDb() { }
Глобальные транзакции (XA) требуют JTA и дополнительной настройки.
Вопрос
Что такое reactive programming в Spring?
Ответ
Reactive programming — парадигма, основанная на асинхронных потоках данных. В Spring WebFlux используется для неблокирующей обработки запросов. Основные типы: Mono (0 или 1 элемент) и Flux (0..N элементов).
Пример контроллера:
@RestController
public class ReactiveController {
@GetMapping("/data")
public Mono<String> getData() {
return Mono.just("Hello");
}
}
Вопрос
В чём разница между Spring MVC и WebFlux?
Ответ
Spring MVC — блокирующий, поток-на-запрос, работает поверх Servlet API.
WebFlux — неблокирующий, событийно-ориентированный, может работать поверх Netty или Servlet 3.1+.
Они несовместимы: нельзя смешивать @Controller с Mono/Flux в MVC и ожидать реактивности.
Вопрос
Что такое WebClient?
Ответ
WebClient — реактивный клиент для выполнения HTTP-запросов. Альтернатива RestTemplate (который устарел). Работает с Mono и Flux.
Пример:
WebClient client = WebClient.create("https://api.example.com");
Mono<User> user = client.get()
.uri("/users/1")
.retrieve()
.bodyToMono(User.class);
Вопрос
Как настроить retry для WebClient?
Ответ
Используется метод .retry() или .retryWhen():
client.get()
.uri("/data")
.retrieve()
.bodyToMono(String.class)
.retryWhen(Retry.fixedDelay(3, Duration.ofSeconds(1)));
Требуется зависимость reactor-extra.
Вопрос
Что такое Circuit Breaker и как его использовать в Spring?
Ответ
Circuit Breaker — паттерн устойчивости, предотвращающий каскадные сбои. В Spring используется через Spring Cloud Circuit Breaker с библиотеками вроде Resilience4J.
Пример:
@CircuitBreaker(name = "externalService", fallbackMethod = "fallback")
public String callExternalService() {
return webClient.get().uri("/api").retrieve().bodyToMono(String.class).block();
}
public String fallback(Exception ex) {
return "default response";
}
Тестирование, мониторинг и продвинутые паттерны
Вопрос
Как протестировать метод с аннотацией @Async?
Ответ
Асинхронные методы тестируются с использованием TestExecutor или ожиданием завершения через CountDownLatch. Лучше всего — интеграционный тест с реальным Executor.
Пример:
@Test
void testAsync() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
service.asyncMethod(latch); // метод вызывает latch.countDown()
assertTrue(latch.await(5, TimeUnit.SECONDS));
}
Или использовать @SpringBootTest с настройкой синхронного исполнителя для тестов.
Вопрос
Что такое @MockBean?
Ответ
@MockBean создаёт Mockito-мок бина и помещает его в контекст Spring, заменяя существующий или добавляя новый. Используется в интеграционных тестах (@SpringBootTest, @WebMvcTest и др.).
Пример:
@SpringBootTest
class ServiceTest {
@MockBean
private ExternalService externalService;
@Test
void test() {
when(externalService.getData()).thenReturn("mock");
// ...
}
}
Вопрос
Как проверить, что метод был вызван в моке?
Ответ
Используется verify() из Mockito:
verify(notificationService).sendEmail("user@example.com");
Можно указать количество вызовов:
verify(repository, times(1)).save(any());
Вопрос
Что такое Spring Boot Actuator?
Ответ
Actuator — модуль Spring Boot для мониторинга и управления приложением в production. Он предоставляет HTTP-эндпоинты (или JMX) для получения информации о здоровье, метриках, конфигурации, логах и т.д.
Основные эндпоинты: /actuator/health, /actuator/metrics, /actuator/env, /actuator/loggers.
Вопрос
Как включить все эндпоинты Actuator?
Ответ
По умолчанию доступны только health и info. Чтобы включить все:
management.endpoints.web.exposure.include=*
Или выборочно:
management.endpoints.web.exposure.include=health,metrics,env,loggers
Вопрос
Как изменить уровень логгера во время выполнения?
Ответ
Через эндпоинт Actuator /actuator/loggers/{name} с POST-запросом:
curl -X POST http://localhost:8080/actuator/loggers/com.example.service \
-H "Content-Type: application/json" \
-d '{"configuredLevel": "DEBUG"}'
Требует включённого эндпоинта loggers.
Вопрос
Что такое health indicator?
Ответ
Health indicator — компонент, проверяющий состояние внешней зависимости (БД, Redis, внешний API). Реализуется через интерфейс HealthIndicator.
Пример:
@Component
public class DatabaseHealthIndicator implements HealthIndicator {
public Health health() {
if (isDatabaseUp()) {
return Health.up().withDetail("database", "Available").build();
}
return Health.down().withDetail("database", "Unavailable").build();
}
}
Результат отображается в /actuator/health.
Вопрос
Как собрать метрики по кастомному методу?
Ответ
Используется Micrometer — библиотека метрик, интегрированная в Spring Boot. Можно применить аннотацию @Timed или внедрить MeterRegistry.
Пример с @Timed:
@Timed(value = "my.service.process", description = "Time spent in process")
public void process() {
// логика
}
Или программно:
@Autowired
private MeterRegistry meterRegistry;
public void customMetric() {
Counter.builder("my.counter").register(meterRegistry).increment();
}
Вопрос
Что такое ApplicationContextInitializer?
Ответ
ApplicationContextInitializer позволяет программно изменять контекст Spring до его обновления. Используется редко — например, для динамической загрузки свойств из секретов или облачного хранилища.
Регистрация:
SpringApplication.addInitializers(new MyContextInitializer());
Вопрос
Как перехватить событие старта приложения?
Ответ
Можно использовать ApplicationRunner или CommandLineRunner:
@Component
public class StartupRunner implements ApplicationRunner {
public void run(ApplicationArguments args) {
// код после полной инициализации контекста
}
}
Или слушатель события ApplicationReadyEvent:
@EventListener
public void onReady(ApplicationReadyEvent event) { ... }
Архитектура и лучшие практики
Вопрос
Как организовать слои в Spring-приложении?
Ответ
Рекомендуется разделение на слои:
- Controller — обработка HTTP-запросов
- Service — бизнес-логика
- Repository — доступ к данным
- Model/Entity — доменные объекты
- DTO — объекты передачи данных между слоями
Каждый слой имеет свою ответственность, зависимости направлены внутрь (от контроллера к репозиторию).
Вопрос
Нужно ли использовать DTO?
Ответ
Да. DTO предотвращают утечку внутренней структуры сущностей наружу, упрощают сериализацию, позволяют гибко формировать ответы и защищают от проблем lazy loading.
Пример:
public record UserDto(String name, String email) {}
Контроллер возвращает UserDto, а не User (JPA-сущность).
Вопрос
Почему не рекомендуется использовать JPA-сущности в контроллерах?
Ответ
JPA-сущности привязаны к состоянию сессии Hibernate. При сериализации вне транзакции могут возникнуть LazyInitializationException. Также сущности содержат внутренние детали (например, @Id, связи), которые не должны быть видны клиенту.
Вопрос
Как обрабатывать ошибки валидации в REST API?
Ответ
Возвращать структурированный JSON с кодом ошибки, сообщением и деталями полей. Использовать глобальный @ControllerAdvice с обработкой MethodArgumentNotValidException.
Пример ответа:
{
"timestamp": "2026-04-01T10:00:00",
"status": 400,
"error": "Validation Failed",
"fields": {
"email": "must be a valid email address"
}
}
Вопрос
Что такое idempotency и как её обеспечить?
Ответ
Idempotency — свойство операции, при котором повторный вызов с теми же параметрами не изменяет результат. Для PUT и DELETE это естественно; для POST — требует дополнительных мер.
Решение: клиент передаёт уникальный Idempotency-Key в заголовке. Сервер сохраняет результат по этому ключу и возвращает его при повторном запросе.
Вопрос
Как реализовать pagination в Spring Data?
Ответ
Используется интерфейс Pageable и возврат Page<T> из репозитория:
@GetMapping("/users")
public Page<User> getUsers(Pageable pageable) {
return userRepository.findAll(pageable);
}
Клиент передаёт параметры: ?page=0&size=20&sort=name,asc.
Вопрос
Что такое projection в Spring Data?
Ответ
Projection — способ выборки только части полей сущности. Может быть интерфейсом или классом.
Пример интерфейса:
public interface UserNameOnly {
String getName();
}
Использование:
List<UserNameOnly> findByName(String name);
Это уменьшает объём данных и повышает производительность.
Вопрос
Как избежать проблемы «open session in view»?
Ответ
Отключить фильтр OpenSessionInViewFilter (в Spring Boot — свойство spring.jpa.open-in-view=false). Вместо этого:
- Загружать все необходимые данные в сервисном слое внутри транзакции
- Использовать
JOIN FETCHили@EntityGraph - Применять DTO
Это предотвращает скрытые N+1 запросы и улучшает производительность.
Вопрос
Как настроить CORS глобально?
Ответ
Реализовать WebMvcConfigurer:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://example.com")
.allowedMethods("GET", "POST", "PUT")
.allowCredentials(true);
}
}
Вопрос
Что такое graceful shutdown в Spring Boot?
Ответ
Graceful shutdown — корректное завершение работы приложения: завершение активных запросов, закрытие соединений, остановка фоновых задач. Включается свойством:
server.shutdown=graceful
Требует поддержки веб-сервера (Tomcat 9.0.33+, Jetty, Netty).
Производительность, масштабируемость и надёжность
Вопрос
Как ускорить запуск Spring Boot-приложения?
Ответ
Методы оптимизации:
- Удалить неиспользуемые стартеры
- Отключить ненужные автоконфигурации (
@SpringBootApplication(exclude = ...)) - Использовать
@Lazyдля тяжёлых бинов - Включить lazy initialization глобально:
spring.main.lazy-initialization=true - Использовать GraalVM native image (через Spring Native)
Вопрос
Что такое Spring Native?
Ответ
Spring Native — проект, позволяющий компилировать Spring Boot-приложение в нативный исполняемый файл с помощью GraalVM. Это даёт мгновенный запуск и низкое потребление памяти, но требует совместимости всех зависимостей.
Вопрос
Как обрабатывать большие объёмы данных без OutOfMemoryError?
Ответ
Использовать потоковую обработку:
- В JPA —
Stream<User> findAllBy(...) - В JDBC —
ResultSetсfetchSize - В WebFlux —
FluxвместоList - Постраничная обработка с
Pageable
Никогда не загружать миллион записей в память целиком.
Вопрос
Как обеспечить идемпотентность REST API?
Ответ
Клиент передаёт уникальный идемпотентный ключ (например, UUID) в заголовке Idempotency-Key. Сервер сохраняет результат операции по этому ключу и возвращает его при повторных запросах с тем же ключом.
Хранить можно в кэше (Redis) с TTL.
Вопрос
Как реализовать retry механизм для внешних вызовов?
Ответ
Использовать Spring Retry или Resilience4J:
@Retryable(value = {RemoteAccessException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000))
public String callExternal() {
// вызов
}
Требует @EnableRetry.
Вопрос
Что такое distributed tracing и как его настроить?
Ответ
Distributed tracing — отслеживание запроса через микросервисы. В Spring используется Sleuth + Zipkin.
Добавляется зависимость spring-cloud-starter-sleuth и spring-cloud-starter-zipkin. Каждый запрос получает traceId и spanId, которые логируются и отправляются в Zipkin UI.
Вопрос
Как логировать структурированно?
Ответ
Использовать JSON-формат логов с полями: timestamp, level, logger, message, traceId, spanId. Настроить Logback или Log4j2 на вывод в JSON.
Пример (Logback):
<encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<timestamp/>
<logLevel/>
<loggerName/>
<message/>
<mdc/> <!-- для traceId -->
</providers>
</encoder>
Вопрос
Как защититься от overposting (mass assignment)?
Ответ
Никогда не принимать сущность JPA напрямую в @RequestBody. Использовать DTO с чётко определёнными полями. Это предотвращает установку внутренних полей (например, role, isAdmin) через JSON.
Вопрос
Как обновлять зависимости Spring Boot безопасно?
Ответ
Использовать spring-boot-dependencies как BOM (Bill of Materials), чтобы гарантировать совместимость версий. Обновлять версию Spring Boot целиком, а не отдельные модули.
Проверять release notes и compatibility matrix перед обновлением.
Вопрос
Как обеспечить обратную совместимость API?
Ответ
Принципы:
- Не удалять поля из ответов
- Делать новые поля опциональными
- Использовать версионирование URL (
/api/v1/...) или заголовков - Поддерживать старые эндпоинты до полного отказа клиентов
- Документировать изменения в changelog