Можно ли внедрить бин в static-поле
Обычная инъекция Spring относится к экземпляру bean. static-поле принадлежит классу, поэтому @Autowired static не является нормальной точкой инъекции и контейнер её не обслуживает как instance field.
// Не рассчитывать на это:
@Autowired
private static Clock clock;Правильный вариант — сделать потребителя bean:
@Component
final class TokenFactory {
private final Clock clock;
TokenFactory(Clock clock) {
this.clock = clock;
}
Token create() {
return new Token(Instant.now(clock));
}
}Если нужен static utility, передать зависимость параметром:
final class TokenRules {
private TokenRules() {}
static boolean expired(Token token, Clock clock) {
return token.expiresAt().isBefore(Instant.now(clock));
}
}Почему workaround плох
Setter экземпляра может присвоить значение в static field, а ApplicationContextAware может положить контекст в глобальный holder. Технически это работает, но создаёт:
- скрытый глобальный lifecycle;
- зависимость от порядка старта/остановки;
- протекание контекста между тестами;
- проблемы при нескольких
ApplicationContext; - возможность обращения до инициализации.
Такой bridge допустим только на жёсткой legacy-границе, с одним владельцем и тестами lifecycle. Это не образец для доменного кода.
На собеседовании
Почему Spring не внедряет static как обычное поле? BeanPostProcessor работает с созданным экземпляром, а static принадлежит классу.
Что выбрать вместо static holder? Constructor injection в экземплярный компонент.
Можно ли вызвать bean из static-метода? Да, если передать зависимость аргументом или вызвать метод через объект-потребитель.
Чем опасен глобальный ApplicationContext holder? Скрытыми зависимостями и некорректным lifecycle.
Связано: static java, Spring Dependency Injection и Inversion of Control, Жизненный цикл бина.