Chamar um método anotado @Bean na configuração do Spring java

98

Estou curioso para saber como a injeção de mola lida com métodos de chamada com a @Beananotação. Se eu colocar uma @Beananotação em um método e retornar uma instância, entendo que isso diz ao spring para criar um bean chamando o método e obtendo a instância retornada. No entanto, às vezes esse bean precisa ser usado para conectar outros beans ou configurar outro código. A maneira usual de fazer isso é chamar o @Beanmétodo anotado para obter uma instância. Minha pergunta é: por que isso não faz com que haja várias instâncias do bean flutuando?

Por exemplo, veja o código abaixo (retirado de outra questão). O entryPoint()método é anotado com @Bean, então eu imagino que o spring criará uma nova instância de BasicAuthenticationEntryPointas a bean. Em seguida, chamamos entryPoint()novamente no bloco configure, mas parece que entryPoint()retorna a instância do bean e não é chamado várias vezes (tentei fazer o log e só consegui uma entrada de log). Potencialmente, poderíamos chamar entryPoint()várias vezes em outras partes da configuração e sempre obteríamos a mesma instância. Meu entendimento disso está correto? Spring faz alguma reescrita mágica de métodos anotados @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();       
}
Markwatson
fonte

Respostas:

130

Sim, a primavera faz alguma mágica . Verifique os Spring Docs :

É aqui que entra a mágica: todas as @Configurationclasses são subclasses no momento da inicialização com CGLIB . Na subclasse, o método filho verifica o contêiner primeiro para quaisquer beans em cache (com escopo definido) antes de chamar o método pai e criar uma nova instância.

Isso significa que as chamadas para @Beanmétodos são proxy via CGLIB e, portanto, a versão em cache do bean é retornada (uma nova não é criada).

O escopo padrão de @Beans é SINGLETON, se você especificar um escopo diferente, como PROTOTYPEa chamada será passada para o método original.

Observe que isso não é válido para métodos estáticos . De acordo com os documentos da primavera:

As chamadas para @Beanmétodos estáticos nunca são interceptadas pelo contêiner, nem mesmo dentro das @Configurationclasses (conforme descrito anteriormente nesta seção), devido a limitações técnicas: a subclasse CGLIB pode substituir apenas métodos não estáticos. Como consequência, uma chamada direta para outro @Beanmétodo tem semântica Java padrão, resultando em uma instância independente sendo retornada diretamente do próprio método de fábrica.

Wassgren
fonte
É possível substituir os beans criados desta forma? Por exemplo, eu tenho uma classe definida pelo Spring que chama diretamente um método de criação de bean. O que eu quero é que não seja usado o bean criado por esse método, mas um que eu mesmo defina (anotando-o com @Beane @Primary).
Fons
4
Mas também me lembro que o proxy (jdk ou CGLIB, o que for) não pode funcionar na auto-invocação, então como @Configuration define a dependência entre os bean? Ele usa exatamente auto-invocação
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. Neste caso, CGLIB cria uma subclasse da classe @Configuration e sobrescreve seus métodos (incluindo o método @Bean). Portanto, quando chamamos o método @Bean de outro método, na verdade chamamos sua versão substituída (graças à vinculação dinâmica de java).
Flame239
Então, o AOP selfInvocation @Componentfuncionará se eu usar o CHLIB para criar proxies em vez de java Poxy?
Antoniossss