Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Кто создаёт Bean в Spring
В Spring IoC контейнере есть иерархия компонентов, которые отвечают за создание и управление бинами. Это не просто волшебство — есть чёткая архитектура.
Главные игроки
1. BeanFactory — базовая фабрика
BeanFactory — это самый низкий уровень, основной интерфейс для создания и получения бинов:
public interface BeanFactory {
Object getBean(String name);
<T> T getBean(String name, Class<T> requiredType);
<T> T getBean(Class<T> requiredType);
boolean containsBean(String name);
boolean isSingleton(String name);
Class<?> getType(String name);
}
Это ленивая фабрика — бины создаются только когда их запрашивают.
2. ApplicationContext — расширенный контейнер
ApplicationContext расширяет BeanFactory и добавляет много функциональности:
public interface ApplicationContext extends BeanFactory, ResourceLoader, EnvironmentCapable {
// Все методы BeanFactory
// Плюс дополнительные возможности
String getDisplayName();
long getStartupDate();
void refresh() throws BeansException;
}
Он создаёт все бины при старте (eager initialization).
3. BeanDefinition — описание бина
Кажды бин описывается BeanDefinition:
public interface BeanDefinition {
String SCOPE_SINGLETON = "singleton";
String SCOPE_PROTOTYPE = "prototype";
// Методы для получения информации о бине
String getBeanClassName();
String getFactoryBeanName();
String getFactoryMethodName();
String getScope();
boolean isSingleton();
boolean isPrototype();
Constructor<?>[] getConstructors();
// ... и ещё много
}
Это полный blueprint того, как нужно создавать бин.
4. BeanDefinitionRegistry — регистр определений
Хранит все BeanDefinition:
public interface BeanDefinitionRegistry {
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);
void removeBeanDefinition(String beanName);
BeanDefinition getBeanDefinition(String beanName);
boolean containsBeanDefinition(String beanName);
String[] getBeanDefinitionNames();
int getBeanDefinitionCount();
}
Процесс создания Bean
Этап 1: Сканирование и регистрация (Registration)
Spring сканирует classpath и создаёт BeanDefinition для каждого найденного класса:
// 1. Spring находит @Component, @Service, @Repository, @Controller
@Component
public class UserService {
// ...
}
// 2. Создаёт BeanDefinition
BeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(UserService.class);
bd.setScope("singleton");
// 3. Регистрирует в BeanDefinitionRegistry
beanDefinitionRegistry.registerBeanDefinition("userService", bd);
Или для @Bean методов:
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserService();
}
}
// Spring создаёт BeanDefinition с factoryMethod="userService"
Этап 2: Инстанцирование (Instantiation)
Главный интерфейс — BeanFactory:
public class SimpleBeanFactory implements BeanFactory {
private Map<String, Object> singletons = new HashMap<>();
private Map<String, BeanDefinition> definitions = new HashMap<>();
public Object getBean(String name) {
// Шаг 1: Проверяем, есть ли уже созданный синглтон
if (singletons.containsKey(name)) {
return singletons.get(name);
}
// Шаг 2: Получаем определение
BeanDefinition bd = definitions.get(name);
// Шаг 3: Инстанцируем через конструктор
Object instance = instantiate(bd);
// Шаг 4: Инжектируем зависимости
autowire(instance, bd);
// Шаг 5: Вызываем инициализацию
initialize(instance, bd);
// Шаг 6: Сохраняем синглтон
singletons.put(name, instance);
return instance;
}
}
Этап 3: Инъекция зависимостей (Dependency Injection)
Это делает AutowireCapableBeanFactory:
public interface AutowireCapableBeanFactory {
// Три способа autowiring
int AUTOWIRE_NO = 0; // Без автоматической инъекции
int AUTOWIRE_BY_NAME = 1; // По имени поля
int AUTOWIRE_BY_TYPE = 2; // По типу
int AUTOWIRE_CONSTRUCTOR = 3; // Через конструктор
Object createBean(Class<?> beanClass);
void autowireBean(Object existingBean);
}
Пример автоматической инъекции:
@Component
public class UserService {
private UserRepository repository; // Помечено @Autowired
@Autowired
public UserService(UserRepository repository) {
this.repository = repository; // Spring автоматически найдёт и инжектит
}
}
Этап 4: Инициализация (Initialization)
Вызываются callback-методы:
@Component
public class DataSource {
@PostConstruct
public void init() {
System.out.println("Initializing DataSource");
// Подключение к БД, загрузка конфигурации, etc.
}
}
Главные классы Spring
DefaultListableBeanFactory — основная реализация:
// Это класс, который на 90% отвечает за создание бинов
public class DefaultListableBeanFactory
extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory,
BeanDefinitionRegistry {
private Map<String, BeanDefinition> beanDefinitions;
private Map<String, Object> singletonObjects;
// Все методы для регистрации и получения бинов
}
AbstractAutowireCapableBeanFactory — логика инъекции:
public abstract class AbstractAutowireCapableBeanFactory {
// Логика autowiring по типу
protected void populateBean(String beanName,
BeanDefinition mbd,
BeanWrapper bw) {
// Ищем все @Autowired поля и методы
// Создаём нужные бины
// Инжектируем их
}
}
ConfigurableApplicationContext — управление жизненным циклом:
public interface ConfigurableApplicationContext extends ApplicationContext {
void refresh() throws BeansException; // Перезагрузить все бины
void close(); // Остановить контейнер и вызвать @PreDestroy
boolean isActive(); // Работает ли контейнер
void registerShutdownHook(); // Регистр при выключении JVM
}
Полный жизненный цикл
1. Spring стартует
↓
2. Сканирует classpath (@ComponentScan)
↓
3. Находит @Component, @Service, @Bean, etc.
↓
4. Создаёт BeanDefinition для каждого
↓
5. Регистрирует в BeanDefinitionRegistry
↓
6. Начинает инстанцирование (в порядке зависимостей)
├─ Вызывает конструктор
├─ Autowiring (инжекция зависимостей)
├─ @PostConstruct методы
└─ Готово к использованию
↓
7. При выключении приложения
├─ Вызывает @PreDestroy методы
└─ Закрывает ресурсы
Реальный пример из Spring
public class Main {
public static void main(String[] args) {
// Это создаёт ApplicationContext
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
// Это вызывает BeanFactory.getBean()
UserService userService = ctx.getBean(UserService.class);
// Spring уже создал все бины, инжектил зависимости
// вызвал @PostConstruct, и теперь можно использовать
userService.createUser("John");
// При завершении программы
((ConfigurableApplicationContext) ctx).close();
// Spring вызовет все @PreDestroy методы
}
}
Итоговая схема
ApplicationContext (главный контейнер)
↓
BeanDefinitionRegistry (хранилище определений)
↓
DefaultListableBeanFactory (основная фабрика)
├─ BeanFactory (создание бинов)
├─ AutowireCapableBeanFactory (инъекция)
└─ ObjectProvider (поиск бинов)
Короче: Spring ApplicationContext это главный ответственный, DefaultListableBeanFactory это рабочая лошадка, которая всё делает на практике.