← Назад к вопросам
Как работает Spring с Bean, если использовать конфигурацию с помощью аннотаций?
2.0 Middle🔥 251 комментариев
#Spring Framework
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как Spring работает с Bean через аннотации
Обзор процесса
Когда ты используешь аннотации для конфигурации Bean, Spring выполняет следующие шаги:
- Component Scanning — сканирование пакетов на предмет аннотированных классов
- Bean Creation — создание экземпляров классов
- Dependency Injection — внедрение зависимостей
- Bean Initialization — инициализация Bean
- Bean Ready — Bean готов к использованию
Шаг 1: Включение Component Scanning
// Способ 1: Через @Configuration + @ComponentScan
@Configuration
@ComponentScan(basePackages = "com.example.app")
public class AppConfig {
// Пусто — сканирование включено
}
// Способ 2: Spring Boot (автоматически)
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// @SpringBootApplication = @Configuration + @ComponentScan + @EnableAutoConfiguration
Шаг 2: Распознание Bean-классов
Spring сканирует пакеты и находит классы с аннотациями:
// Эти аннотации регистрируют класс как Bean
@Component // Базовая аннотация
public class MyComponent { }
@Service // Для бизнес-логики
public class UserService { }
@Repository // Для доступа к данным
public class UserRepository { }
@Controller // Для web-контроллеров
public class UserController { }
@RestController // Для REST API
public class ApiController { }
@Configuration // Для конфигурации
public class AppConfig { }
Все они — подтипы @Component, Spring их одинаково обрабатывает:
// Внутренне
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {
String value() default "";
}
// Аннотирована @Component
Шаг 3: Создание Bean экземпляра
@Service
public class UserService {
public UserService() {
System.out.println("UserService создан");
}
}
@Repository
public class UserRepository {
public UserRepository() {
System.out.println("UserRepository создан");
}
}
Внутренний процесс:
// Примерная реализация (внутри Spring)
public class BeanFactory {
public Object createBean(Class<?> beanClass) throws Exception {
// 1. Получить конструктор
Constructor<?> constructor = beanClass.getDeclaredConstructor();
// 2. Создать экземпляр через рефлексию
Object instance = constructor.newInstance();
// 3. Вернуть экземпляр
return instance;
}
}
Шаг 4: Dependency Injection (DI)
Spring анализирует конструкторы и поля, затем внедряет зависимости:
@Service
public class UserService {
// Способ 1: Constructor Injection (рекомендуется)
private final UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
}
}
@Service
public class OrderService {
// Способ 2: Setter Injection
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
}
@Service
public class PaymentService {
// Способ 3: Field Injection (не рекомендуется)
@Autowired
private UserService userService;
}
Внутренняя логика:
// Примерная реализация (упрощённо)
public class BeanFactory {
private Map<String, Object> beans = new HashMap<>();
public void registerBeans(String[] packageNames) {
// Сканировать пакеты
Set<Class<?>> annotatedClasses = findAnnotatedClasses(packageNames);
// Создать Bean для каждого класса
for (Class<?> clazz : annotatedClasses) {
Object bean = createBean(clazz);
beans.put(getBeanName(clazz), bean);
}
}
public Object createBean(Class<?> clazz) {
// Получить конструктор с наибольшим количеством параметров
Constructor<?> constructor = selectConstructor(clazz);
// Найти зависимости для параметров конструктора
Object[] dependencies = resolveDependencies(constructor.getParameterTypes());
// Создать экземпляр
Object instance = constructor.newInstance(dependencies);
// Обработать @Autowired на полях
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
Object dependency = beans.get(field.getType());
field.setAccessible(true);
field.set(instance, dependency);
}
}
return instance;
}
}
Шаг 5: Управление жизненным циклом
Spring поддерживает callback-методы для управления жизненным циклом Bean:
@Service
public class UserService implements InitializingBean, DisposableBean {
// Способ 1: Через интерфейсы
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Bean инициализирован");
// Здесь инициализировать ресурсы
}
@Override
public void destroy() throws Exception {
System.out.println("Bean уничтожается");
// Здесь закрывать ресурсы
}
}
@Service
public class PaymentService {
// Способ 2: Через аннотации
@PostConstruct
public void init() {
System.out.println("PaymentService инициализирован");
}
@PreDestroy
public void cleanup() {
System.out.println("PaymentService уничтожается");
}
}
@Service
public class OrderService {
// Способ 3: Через @Bean аннотацию в конфигурации
@Bean(initMethod = "init", destroyMethod = "cleanup")
public OrderService orderService() {
return new OrderService();
}
}
Порядок инициализации Bean
// 1. Создание
public UserService() {
System.out.println("1. Конструктор");
}
// 2. Внедрение зависимостей
@Autowired
Public void setRepository(UserRepository repo) {
System.out.println("2. Injection");
}
// 3. Инициализация
@PostConstruct
public void init() {
System.out.println("3. Init");
}
// Порядок вывода: 1, 2, 3
Пример полного цикла
// 1. Конфигурация
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}
// 2. Repository
@Repository
public class UserRepository {
public UserRepository() {
System.out.println("1. UserRepository constructor");
}
@PostConstruct
public void init() {
System.out.println("3. UserRepository init");
}
}
// 3. Service
@Service
public class UserService {
private final UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
System.out.println("2. UserService constructor");
}
@PostConstruct
public void init() {
System.out.println("4. UserService init");
}
}
// 4. Controller
@RestController
public class UserController {
private final UserService service;
public UserController(UserService service) {
this.service = service;
System.out.println("5. UserController constructor");
}
}
// Вывод при запуске:
// 1. UserRepository constructor
// 3. UserRepository init
// 2. UserService constructor
// 4. UserService init
// 5. UserController constructor
Bean Scope
Spring управляет жизненным циклом Bean в зависимости от scope:
@Service
@Scope("singleton") // По умолчанию — один экземпляр на весь контекст
public class UserService {
}
@Service
@Scope("prototype") // Новый экземпляр при каждом запросе
public class RequestHandler {
}
@Service
@Scope("request") // Новый экземпляр для каждого HTTP запроса
public class UserContext {
}
@Service
@Scope("session") // Один экземпляр на HTTP-сессию
public class SessionData {
}
Итог
При использовании аннотаций Spring:
- Сканирует классы с @Component, @Service, @Repository и другими аннотациями
- Создаёт экземпляры через рефлексию
- Разрешает зависимости и внедряет их
- Инициализирует Bean через @PostConstruct методы
- Управляет жизненным циклом согласно Scope
- Уничтожает при завершении контекста через @PreDestroy
Это всё происходит автоматически — разработчику нужно только аннотировать классы!