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

2022-08-31 08:30:15

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

例如,请参阅下面的代码(取自另一个问题)。该方法用 注释,因此我想象 spring 将创建一个新的 bean 实例。然后,我们在配置块中再次调用,但它似乎返回了bean实例,并且没有多次调用(我尝试了日志记录,但只得到了一个日志条目)。我们可能在配置的其他部分中多次调用,并且我们总是会得到相同的实例。我对此的理解是否正确?春天是否做了一些神奇的重写方法注释?entryPoint()@BeanBasicAuthenticationEntryPointentryPoint()entryPoint()entryPoint()@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();       
}

答案 1

是的,春天有一些魔力。查看春季文档

这就是魔力所在:所有类都在启动时使用CGRIB进行子类化。在子类中,子方法首先检查容器中是否有任何缓存(作用域)的 Bean,然后再调用父方法并创建新实例。@Configuration

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

s 的默认作用域是 ,如果指定不同的作用域,例如调用将传递给原始方法。@BeanSINGLETONPROTOTYPE

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

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


答案 2

推荐