← Назад к вопросам

Как устроен жизненный цикл Spring приложений?

2.0 Middle🔥 201 комментариев
#Spring Framework

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Жизненный цикл Spring приложений

Жизненный цикл Spring приложения — это последовательность этапов инициализации и выключения контейнера Bean, управления зависимостями и выполнения хуков на каждом этапе.

Фазы жизненного цикла

1. Инициализация (Bootstrapping)

Создание контекста (ApplicationContext):

ApplicationContext context = new ClassPathXmlApplicationContext(
    "applicationContext.xml"
);

// или с Java конфигом
ApplicationContext context = new AnnotationConfigApplicationContext(
    AppConfig.class
);

Что происходит:

  • Spring читает конфигурацию (XML, Java config, properties)
  • Создаёт bean definitions для каждого bean-а
  • Инициализирует сам контейнер

2. Bean Instantiation (Создание экземпляров)

Фазы для каждого bean-а:

а) Создание объекта:

  • Spring использует рефлексию или конструктор
  • Если задан factory-method, то используется он

б) Dependency Injection:

@Component
public class UserService {
    private final UserRepository repository;
    
    // Constructor injection (рекомендуется)
    public UserService(UserRepository repository) {
        this.repository = repository;
    }
}

в) Setter injection:

@Component
public class OrderService {
    private PaymentService paymentService;
    
    @Autowired
    public void setPaymentService(PaymentService service) {
        this.paymentService = service;
    }
}

3. Bean Post-Processing

BeanPostProcessor интерфейс:

@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("Before init: " + beanName);
        return bean; // можно вернуть другой bean
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("After init: " + beanName);
        return bean;
    }
}

Примеры BeanPostProcessor:

  • @Autowired обработчик
  • @ConfigurationProperties обработчик
  • AOP proxies

4. Инициализация Bean-а

Способ 1: @PostConstruct аннотация (рекомендуется):

@Component
public class DatabaseConnection {
    @PostConstruct
    public void init() {
        System.out.println("Инициализация подключения к БД");
        // подключение, загрузка данных, и т.д.
    }
}

Способ 2: InitializingBean интерфейс:

@Component
public class OldStyleService implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Bean инициализирован");
    }
}

Способ 3: init-method в конфиге:

@Configuration
public class AppConfig {
    @Bean(initMethod = "init")
    public MyService myService() {
        return new MyService();
    }
}

5. Использование Bean-а

@Service
public class UserController {
    private final UserService userService;
    
    public UserController(UserService userService) {
        this.userService = userService; // готов к использованию
    }
    
    public void getUser(Long id) {
        User user = userService.findById(id);
    }
}

6. Деструкция (Shutdown)

При выключении приложения:

BeanPostProcessor для деструкции:

@Component
public class ShutdownBeanPostProcessor implements BeanPostProcessor {
    // Вызывается перед разрушением
}

Способ 1: @PreDestroy аннотация (рекомендуется):

@Component
public class DatabaseConnection {
    @PreDestroy
    public void destroy() {
        System.out.println("Закрытие подключения к БД");
        // закрытие ресурсов
    }
}

Способ 2: DisposableBean интерфейс:

@Component
public class ResourceManager implements DisposableBean {
    @Override
    public void destroy() throws Exception {
        System.out.println("Освобождение ресурсов");
    }
}

Способ 3: destroyMethod в конфиге:

@Configuration
public class AppConfig {
    @Bean(destroyMethod = "close")
    public DataSource dataSource() {
        return new DataSource();
    }
}

Полный цикл Bean-а

1. BeanNameAware.setBeanName()
2. BeanClassLoaderAware.setBeanClassLoader()
3. BeanFactoryAware.setBeanFactory()
4. ApplicationContextAware.setApplicationContext()
5. BeanPostProcessor.postProcessBeforeInitialization()
6. @PostConstruct / InitializingBean.afterPropertiesSet()
7. BeanPostProcessor.postProcessAfterInitialization()
[Bean готов к использованию]
8. @PreDestroy / DisposableBean.destroy()

Практический пример

@Component
public class CompleteLifecycleBean 
    implements InitializingBean, DisposableBean, 
    ApplicationContextAware, BeanNameAware {
    
    private String beanName;
    private ApplicationContext context;
    
    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("1. setBeanName: " + name);
    }
    
    @Override
    public void setApplicationContext(ApplicationContext ctx) {
        this.context = ctx;
        System.out.println("2. setApplicationContext");
    }
    
    @PostConstruct
    public void postConstruct() {
        System.out.println("3. @PostConstruct");
    }
    
    @Override
    public void afterPropertiesSet() {
        System.out.println("4. afterPropertiesSet");
    }
    
    public void doSomething() {
        System.out.println("5. Bean используется");
    }
    
    @PreDestroy
    public void preDestroy() {
        System.out.println("6. @PreDestroy");
    }
    
    @Override
    public void destroy() {
        System.out.println("7. destroy()");
    }
}

Рекомендации

  • Используй @PostConstruct/@PreDestroy — это стандарт Jakarta EE
  • Избегай InitializingBean/DisposableBean — старый подход
  • Не делай тяжёлую логику в конструкторе — это усложняет тестирование
  • Используй constructor injection вместо field injection