在 Spring java 配置中调用 @Bean 注释方法

Calling a @Bean annotated method in Spring java configuration

我很好奇 spring 注入如何处理带有 @Bean 注释的调用方法。如果我在一个方法上放置一个 @Bean 注释,并在一个实例上放置 return,我明白这告诉 spring 通过调用该方法并获取 returned 创建一个 bean实例。但是,有时该 bean 必须用于连接其他 bean 或设置其他代码。完成此操作的通常方法是调用 @Bean 注释方法来获取实例。我的问题是,为什么这不会导致有多个 bean 实例浮动?

例如,请参阅下面的代码(摘自另一个问题)。 entryPoint() 方法用 @Bean 注释,所以我想 spring 将创建一个新的 BasicAuthenticationEntryPoint 实例作为 bean。然后,我们在 configure 块中再次调用 entryPoint(),但似乎 entryPoint() return 是 bean 实例,并且没有被多次调用(我尝试记录,但只有一个日志条目)。潜在地,我们可以在配置的其他部分多次调用 entryPoint(),并且我们总是会得到相同的实例。我对此的理解正确吗? spring 是否对用 @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();       
}

是的,Spring 做了一些 魔法。检查 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.

这意味着对 @Bean 方法的调用是通过 CGLIB 代理的,因此会返回 bean 的缓存版本(不会创建新版本)。

@Beans 的默认范围是 SINGLETON,如果您指定不同的范围,例如 PROTOTYPE,调用将被传递到原始方法。

请注意,这对静态方法无效。根据 spring 文档:

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.