Вызов аннотированного метода @Bean в конфигурации Java Spring


102

Мне любопытно, как Spring Injection обрабатывает методы вызова с @Beanаннотацией. Если я помещаю @Beanаннотацию к методу и возвращаю экземпляр, я понимаю, что это говорит Spring создать bean-компонент путем вызова метода и получения возвращенного экземпляра. Однако иногда этот компонент необходимо использовать для подключения других компонентов или для настройки другого кода. Обычно это делается путем вызова @Beanаннотированного метода для получения экземпляра. У меня вопрос: почему это не приводит к тому, что вокруг плавает несколько экземпляров bean-компонента?

Например, посмотрите код ниже (взятый из другого вопроса). Этот entryPoint()метод аннотирован @Bean, поэтому я предполагаю, что Spring создаст новый экземпляр BasicAuthenticationEntryPointкак bean-компонент. Затем мы entryPoint()снова вызываем блок настройки, но похоже, что он entryPoint()возвращает экземпляр компонента и не вызывается несколько раз (я пробовал вести журнал и получил только одну запись в журнале). Потенциально мы можем вызывать 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();       
}

Ответы:


134

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

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

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

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

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

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


Можно ли переопределить bean-компоненты, созданные таким образом? Например, у меня есть класс, определенный Spring, который напрямую вызывает метод создания bean-компонента. Я хочу, чтобы использовался не компонент, созданный этим методом, а тот, который я определяю сам (путем аннотирования его с помощью @Beanи @Primary).
Fons

4
Но я также напоминаю, что прокси (jdk или CGLIB, в зависимости от того, что) не может работать в режиме самовызова, поэтому как @Configuration определяет зависимость между компонентами? Он использует именно само-вызов
Nowhy

3
@Nowhy CGLib allows us to create proxy classes at runtime by creating sub class of specified class using Byte code generation. CGLib proxies are used in the case where Proxy is to be created for those class which does not have any interfaces or have methods which are not declared in the implementing interface. В этом случае CGLIB создает подкласс класса @Configuration и переопределяет его методы (включая метод @Bean). Таким образом, когда мы вызываем метод @Bean из другого метода, мы фактически вызываем его замененную версию (благодаря динамической привязке java).
Flame239 08

Так будет ли selfInvocation AOP @Componentработать, если я использую CHLIB для создания прокси вместо java Poxy?
Антониосс
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.