ChatGPT解决这个技术问题 Extra ChatGPT

Calling a @Bean annotated method in Spring java configuration

I'm curious about how spring injection handles calling methods with the @Bean annotation. If I put a @Bean annotation on a method, and return an instance, I understand that that tells spring to create a bean by calling the method and getting the returned instance. However, sometimes that bean has to be used to wire other beans or setup other code. The usual way this is done is to call the @Bean annotated method to get an instance. My question is, why doesn't this cause there to be multiple instances of the bean floating around?

For example, see the code below (taken from another question). The entryPoint() method is annotated with @Bean, so I would imagine spring will create a new instance of BasicAuthenticationEntryPoint as a bean. Then, we call entryPoint() again in the configure block, but it seems like entryPoint() returns the bean instance, and isn't called multiple times (I tried logging, and only got one log entry). Potentially we could call entryPoint() multiple times in other parts of the configuration, and we would always get the same instance. Is my understanding of this correct? Does spring do some magical rewriting of methods annotated with @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();       
}

J
Julian Cardenas

Yes, Spring does some magic. Check the Spring Docs:

This is where the magic comes in: All @Configuration classes are subclassed at startup-time with CGLIB. In the subclass, the child method checks the container first for any cached (scoped) beans before it calls the parent method and creates a new instance.

This means that the calls to @Bean methods are proxied via CGLIB and therefore the cached version of the bean is returned (a new one is not created).

The default scope of @Beans is SINGLETON, if you specify a different scope such as PROTOTYPE the call will be passed to the original method.

Please note that this is not valid for static methods. As per the spring docs:

Calls to static @Bean methods never get intercepted by the container, not even within @Configuration classes (as described earlier in this section), due to technical limitations: CGLIB subclassing can override only non-static methods. As a consequence, a direct call to another @Bean method has standard Java semantics, resulting in an independent instance being returned straight from the factory method itself.


Is it possible to override beans created this way? For example, I have a Spring defined class that directly calls a bean creation method. What I want is that not the bean created by that method is used, but one I define myself (by annotating it with @Bean and @Primary).
But I also recall that proxy(jdk or CGLIB, whichever) can not working in self-invocation, so how does @Configuration define inter-bean dependency? It uses exactly self-invocation
@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 this case, CGLIB creates subclass of @Configuration class and overrides its methods (including @Bean method). Thus, when we call @Bean method from another method, we actually call its overriden version(thanks to java dynamic binding).
So will selfInvocation AOP in @Component will work if I use CHLIB to create proxies instead of java Poxy ?