Подтвердить что ты не робот

Вызов аннотированного метода @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();       
}
4b9b3361

Ответ 1

Да, spring творит чудеса. Проверьте документы Spring:

В этом и заключается магия: все классы @Configuration подклассируются во время запуска с помощью CGLIB. В подклассе дочерний метод сначала проверяет контейнер на наличие кэшированных (ограниченных) bean-компонентов, а затем вызывает родительский метод и создает новый экземпляр.

Это означает, что вызовы методов @Bean передаются через CGLIB и, следовательно, возвращается кэшированная версия компонента (новая не создается).

Область @Bean по @Bean - SINGLETON, если вы укажете другую область, такую как PROTOTYPE вызов будет передан исходному методу.

Обратите внимание, что это недопустимо для статических методов. Согласно весенним документам:

Вызовы статических методов @Bean никогда не перехватываются контейнером, даже внутри классов @Configuration (как описано ранее в этом разделе), из-за технических ограничений: подклассы CGLIB могут переопределять только нестатические методы. Как следствие, прямой вызов другого метода @Bean имеет стандартную семантику Java, в результате чего независимый экземпляр возвращается непосредственно из самого метода фабрики.