Chiamata a un metodo annotato @Bean nella configurazione Java di Spring


101

Sono curioso di sapere come Spring injection gestisce i metodi di chiamata con l' @Beanannotazione. Se metto @Beanun'annotazione su un metodo e restituisco un'istanza, capisco che ciò dice a spring di creare un bean chiamando il metodo e ottenendo l'istanza restituita. Tuttavia, a volte quel bean deve essere utilizzato per collegare altri bean o impostare altro codice. Il modo usuale per farlo è chiamare il @Beanmetodo annotato per ottenere un'istanza. La mia domanda è: perché questo non causa la presenza di più istanze del fagiolo in giro?

Ad esempio, vedere il codice seguente (tratto da un'altra domanda). Il entryPoint()metodo è annotato con @Bean, quindi immagino che spring creerà una nuova istanza di BasicAuthenticationEntryPointas a bean. Quindi, chiamiamo di entryPoint()nuovo nel blocco configure, ma sembra che entryPoint()restituisca l'istanza del bean e non venga chiamato più volte (ho provato a eseguire il log e ho ottenuto solo una voce di log). Potenzialmente potremmo chiamare entryPoint()più volte in altre parti della configurazione e avremmo sempre la stessa istanza. La mia comprensione di questo è corretta? La primavera fa qualche magica riscrittura di metodi annotati con @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();       
}

Risposte:


134

Sì, la primavera fa un po 'di magia . Controlla i documenti di primavera :

È qui che entra in gioco la magia: tutte le @Configurationclassi sono sottoclassi all'avvio con CGLIB . Nella sottoclasse, il metodo figlio controlla prima il contenitore per eventuali bean memorizzati nella cache (con ambito) prima di chiamare il metodo padre e creare una nuova istanza.

Ciò significa che le chiamate ai @Beanmetodi vengono trasmesse tramite proxy tramite CGLIB e quindi viene restituita la versione memorizzata nella cache del bean (non ne viene creata una nuova).

L'ambito predefinito di @Beans è SINGLETON, se si specifica un ambito diverso, ad esempio PROTOTYPEla chiamata verrà passata al metodo originale.

Si noti che questo non è valido per i metodi statici . Come da documenti di primavera:

Le chiamate a @Beanmetodi statici non vengono mai intercettate dal contenitore, nemmeno all'interno delle @Configurationclassi (come descritto in precedenza in questa sezione), a causa di limitazioni tecniche: le sottoclassi CGLIB possono sovrascrivere solo metodi non statici. Di conseguenza, una chiamata diretta a un altro @Beanmetodo ha una semantica Java standard, risultando in un'istanza indipendente restituita direttamente dal metodo factory stesso.


È possibile sovrascrivere i bean creati in questo modo? Ad esempio, ho una classe definita Spring che chiama direttamente un metodo di creazione del bean. Quello che voglio è che non venga utilizzato il bean creato con quel metodo, ma uno che definisco me stesso (annotandolo con @Beane @Primary).
Fons

4
Ma ricordo anche che il proxy (jdk o CGLIB, a seconda di quale) non può funzionare nell'auto-invocazione, quindi come fa @Configuration a definire la dipendenza tra i bean? Usa esattamente l'
autoinvocazione

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. In questo caso, CGLIB crea una sottoclasse della classe @Configuration e sovrascrive i suoi metodi (incluso il metodo @Bean). Pertanto, quando chiamiamo il metodo @Bean da un altro metodo, in realtà chiamiamo la sua versione sovrascritta (grazie all'associazione dinamica java).
Flame239

Quindi selfInvocation AOP @Componentfunzionerà se utilizzo CHLIB per creare proxy invece di java Poxy?
Antoniossss
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.