Appel d'une méthode annotée @Bean dans la configuration Java Spring

100

Je suis curieux de savoir comment l'injection de ressort gère les méthodes d'appel avec l' @Beanannotation. Si je mets une @Beanannotation sur une méthode et renvoie une instance, je comprends que cela indique à spring de créer un bean en appelant la méthode et en obtenant l'instance retournée. Cependant, parfois, ce bean doit être utilisé pour câbler d'autres beans ou configurer un autre code. La manière habituelle de procéder consiste à appeler la @Beanméthode annotée pour obtenir une instance. Ma question est la suivante: pourquoi cela ne cause-t-il pas plusieurs instances du haricot flottant?

Par exemple, consultez le code ci-dessous (tiré d'une autre question). La entryPoint()méthode est annotée avec @Bean, donc j'imagine que Spring créera une nouvelle instance de en BasicAuthenticationEntryPointtant que bean. Ensuite, nous appelons à entryPoint()nouveau dans le bloc de configuration, mais il semble que cela entryPoint()renvoie l'instance du bean et ne soit pas appelée plusieurs fois (j'ai essayé de se connecter et je n'ai obtenu qu'une seule entrée de journal). Potentiellement, nous pourrions appeler entryPoint()plusieurs fois dans d'autres parties de la configuration, et nous obtiendrions toujours la même instance. Est-ce que ma compréhension de cela est correcte? Spring fait-il une réécriture magique des méthodes annotées avec @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
la source

Réponses:

133

Oui, le printemps fait de la magie . Consultez les documents Spring :

C'est là que la magie entre en jeu: toutes les @Configurationclasses sont sous- classées au démarrage avec CGLIB . Dans la sous-classe, la méthode enfant vérifie d'abord le conteneur pour tous les beans mis en cache (étendus) avant d'appeler la méthode parent et de créer une nouvelle instance.

Cela signifie que les appels aux @Beanméthodes sont proxy via CGLIB et donc la version mise en cache du bean est retournée (une nouvelle n'est pas créée).

La portée par défaut de @Beans est SINGLETON, si vous spécifiez une portée différente telle que PROTOTYPEl'appel sera passé à la méthode d'origine.

Veuillez noter que cela n'est pas valable pour les méthodes statiques . Selon les documents du printemps:

Les appels aux @Beanméthodes statiques ne sont jamais interceptés par le conteneur, pas même au sein des @Configurationclasses (comme décrit plus haut dans cette section), en raison de limitations techniques: le sous-classement CGLIB ne peut remplacer que les méthodes non statiques. En conséquence, un appel direct à une autre @Beanméthode a une sémantique Java standard, résultant en une instance indépendante renvoyée directement à partir de la méthode d'usine elle-même.

Wassgren
la source
Est-il possible de remplacer les beans créés de cette façon? Par exemple, j'ai une classe définie par Spring qui appelle directement une méthode de création de bean. Ce que je veux, c'est que ce ne soit pas le bean créé par cette méthode, mais celui que je définis moi-même (en l'annotant avec @Beanet @Primary).
Fons
4
Mais je rappelle également que le proxy (jdk ou CGLIB, selon le cas) ne peut pas fonctionner en auto-invocation, alors comment @Configuration définit-il la dépendance inter-bean? Il utilise exactement l'auto-invocation
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. Dans ce cas, CGLIB crée une sous-classe de la classe @Configuration et remplace ses méthodes (y compris la méthode @Bean). Ainsi, lorsque nous appelons la méthode @Bean à partir d'une autre méthode, nous appelons en fait sa version surchargée (grâce à la liaison dynamique java).
Flame239
Est-ce que selfInvocation AOP @Componentfonctionnera si j'utilise CHLIB pour créer des proxies au lieu de java Poxy?
Antoniossss le