在 Springjava 配置中调用带@Bean 注释的方法

我很好奇 Spring 注入是如何使用 @Bean注释处理调用方法的。如果我在一个方法上放入一个 @Bean注释,并返回一个实例,我理解这会通过调用该方法并获取返回的实例来告诉 spring 创建一个 bean。但是,有时必须使用该 bean 连接其他 bean 或设置其他代码。通常的方法是调用 @Bean注释方法来获得一个实例。我的问题是,为什么这不会导致 bean 的多个实例到处漂浮呢?

例如,请参阅下面的代码(摘自另一个问题)。entryPoint()方法使用 @Bean进行注释,因此我想 Spring 将创建一个新的 BasicAuthenticationEntryPoint实例作为 bean。然后,我们在 configure 块中再次调用 entryPoint(),但似乎 entryPoint()返回了 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();
}
61977 次浏览

是的,Spring 做了一些 魔法。检查 Spring Docs:

这就是奇迹发生的地方: 所有的 @Configuration类在启动时与 CGLIB一起被子类化。在子类中,子方法在调用父方法并创建新实例之前,首先检查容器是否存在任何缓存(作用域) bean。

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

@Beans 的默认作用域是 SINGLETON,如果您指定一个不同的作用域,例如 PROTOTYPE,那么调用将被传递给原始方法。

请注意,这是 对静态方法无效。根据春季文件:

由于技术限制,对静态 @Bean方法的调用永远不会被容器拦截,甚至在 @Configuration类中也不会被拦截(如本节前面所述) : CGLIB 子类化只能覆盖非静态方法。因此,对另一个 @Bean方法的直接调用具有标准的 Java 语义,导致直接从工厂方法本身返回独立实例。