Что гарантированно проинициализировано к моменту вызова метода, помеченного @PostConstruct в Spring?

«Что гарантированно проинициализировано к моменту вызова метода, помеченного @PostConstruct в Spring?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Метод, аннотированный @PostConstruct, вызывается после того, как Spring полностью внедрит все зависимости (проведёт инъекцию) в бин, но до того, как бин будет готов к использованию клиентом.

С чем можно взаимодействовать:

  • Все поля бина, помеченные @Autowired, @Inject или @Resource. К этому моменту они уже проинициализированы.
  • Состояние самого бина. Вы можете безопасно выполнять настройку на основе инжектированных зависимостей.

Пример:

@Service
public class CacheService {

    @Autowired
    private SomeRepository repository; // Уже инжектирован
    private Map<String, Data> cache;

    @PostConstruct
    public void initCache() {
        // Можно использовать repository
        List<Data> data = repository.findAll();
        this.cache = data.stream()
                         .collect(Collectors.toMap(Data::getId, Function.identity()));
    }
}

Важные ограничения и «нельзя»:

  1. Нет гарантий порядка между @PostConstruct разных бинов, если он не задан явно через @DependsOn.
  2. Контекст транзакций ещё не активен. Нельзя выполнять операции, требующие транзакционность.
  3. Не стоит выполнять долгие операции, так как это задержит полную инициализацию контекста приложения.
  4. Бин ещё не прошёл через возможные Spring AOP-прокси, поэтому вызовы методов внутри @PostConstruct не будут перехватываться advice'ами (если только это не self-injection).