Llamar a un método anotado @Bean en la configuración de Spring java

101

Tengo curiosidad sobre cómo la inyección de resorte maneja los métodos de llamada con la @Beananotación. Si pongo una @Beananotación en un método y devuelvo una instancia, entiendo que eso le dice a Spring que cree un bean llamando al método y obteniendo la instancia devuelta. Sin embargo, a veces ese bean debe usarse para conectar otros beans o configurar otro código. La forma habitual de hacer esto es llamar al @Beanmétodo anotado para obtener una instancia. Mi pregunta es, ¿por qué esto no causa que haya múltiples instancias del bean flotando?

Por ejemplo, vea el código a continuación (tomado de otra pregunta). El entryPoint()método está anotado con @Bean, así que imagino que spring creará una nueva instancia de BasicAuthenticationEntryPointcomo un bean. Luego, volvemos a llamar entryPoint()en el bloque de configuración, pero parece que entryPoint()devuelve la instancia del bean y no se llama varias veces (intenté iniciar sesión y solo obtuve una entrada de registro). Potencialmente, podríamos llamar entryPoint()varias veces en otras partes de la configuración y siempre obtendríamos la misma instancia. ¿Es correcto mi entendimiento de esto? ¿Spring hace una reescritura mágica de los 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
fuente

Respuestas:

134

Sí, Spring hace algo de magia . Consulte los documentos de primavera :

Aquí es donde entra la magia: todas las @Configurationclases se subclasifican en el momento del inicio con CGLIB . En la subclase, el método hijo comprueba primero el contenedor en busca de beans almacenados en caché (con ámbito) antes de llamar al método padre y crear una nueva instancia.

Esto significa que las llamadas a los @Beanmétodos se transfieren a través de CGLIB y, por lo tanto, se devuelve la versión en caché del bean (no se crea una nueva).

El alcance predeterminado de @Beans es SINGLETON, si especifica un alcance diferente, como PROTOTYPEla llamada se pasará al método original.

Tenga en cuenta que esto no es válido para métodos estáticos . Según los documentos de primavera:

Las llamadas a @Beanmétodos estáticos nunca son interceptadas por el contenedor, ni siquiera dentro de las @Configurationclases (como se describió anteriormente en esta sección), debido a limitaciones técnicas: la subclasificación CGLIB puede anular solo los métodos no estáticos. Como consecuencia, una llamada directa a otro @Beanmétodo tiene semántica estándar de Java, lo que da como resultado una instancia independiente que se devuelve directamente desde el método de fábrica.

wassgren
fuente
¿Es posible anular los beans creados de esta manera? Por ejemplo, tengo una clase definida por Spring que llama directamente a un método de creación de frijoles. Lo que quiero es que no se use el bean creado por ese método, sino uno que yo mismo defino (anotándolo con @Beany @Primary).
Fons
4
Pero también recuerdo que el proxy (jdk o CGLIB, lo que sea) no puede funcionar en la auto-invocación, entonces, ¿cómo define @Configuration la dependencia entre beans? Utiliza exactamente la
autoinvocación
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. En este caso, CGLIB crea una subclase de la clase @Configuration y anula sus métodos (incluido el método @Bean). Por lo tanto, cuando llamamos al método @Bean desde otro método, en realidad llamamos a su versión anulada (gracias al enlace dinámico de Java).
Flame239
Entonces, ¿el AOP de autoinvocación @Componentfuncionará si uso CHLIB para crear proxies en lugar de java Poxy?
Antoniossss