Вызов аннотированного метода @Bean в конфигурации Spring java
Мне интересно, как spring инъекция обрабатывает методы вызова с помощью аннотации @Bean
. Если я помещаю аннотацию @Bean
в метод и возвращаю экземпляр, я понимаю, что он сообщает spring создать bean, вызвав метод и получив возвращаемый экземпляр. Однако иногда bean должен использоваться для подключения другого beans или установки другого кода. Обычно это делается, чтобы вызвать аннотированный метод @Bean
для получения экземпляра. Мой вопрос заключается в том, почему это не приводит к тому, что несколько экземпляров bean плавают вокруг?
Например, см. код ниже (взятый из другого вопроса). Метод entryPoint()
аннотируется с @Bean
, поэтому я бы предположил, что spring создаст новый экземпляр BasicAuthenticationEntryPoint
как bean. Затем мы вызываем entryPoint()
снова в блоке configure, но, похоже, entryPoint()
возвращает экземпляр bean и не вызывается несколько раз (я пробовал вести журнал и получал только одну запись в журнале). Потенциально мы могли бы называть entryPoint()
несколько раз в других частях конфигурации, и мы всегда будем иметь один и тот же экземпляр. Насколько я понимаю это правильно? Выполняет ли spring магическое переписывание методов, аннотированных с помощью @Bean
?
@Bean
public BasicAuthenticationEntryPoint entryPoint() {
BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
basicAuthEntryPoint.setRealmName("My Realm");
return basicAuthEntryPoint;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(entryPoint())
.and()
.authorizeUrls()
.anyRequest().authenticated()
.and()
.httpBasic();
}
Ответы
Ответ 1
Да, spring творит чудеса. Проверьте документы Spring:
В этом и заключается магия: все классы @Configuration
подклассируются во время запуска с помощью CGLIB. В подклассе дочерний метод сначала проверяет контейнер на наличие кэшированных (ограниченных) bean-компонентов, а затем вызывает родительский метод и создает новый экземпляр.
Это означает, что вызовы методов @Bean
передаются через CGLIB и, следовательно, возвращается кэшированная версия компонента (новая не создается).
Область @Bean
по @Bean
- SINGLETON
, если вы укажете другую область, такую как PROTOTYPE
вызов будет передан исходному методу.
Обратите внимание, что это недопустимо для статических методов. Согласно весенним документам:
Вызовы статических методов @Bean
никогда не перехватываются контейнером, даже внутри классов @Configuration
(как описано ранее в этом разделе), из-за технических ограничений: подклассы CGLIB могут переопределять только нестатические методы. Как следствие, прямой вызов другого метода @Bean
имеет стандартную семантику Java, в результате чего независимый экземпляр возвращается непосредственно из самого метода фабрики.