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


98

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

例如,请参见下面的代码(来自另一个问题)。该entryPoint()方法带有注释@Bean,因此我可以想象spring将创建一个BasicAuthenticationEntryPointas的新实例。然后,我们entryPoint()在configure块中再次调用,但是似乎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();       
}

Answers:


130

是的,Spring做些魔术。查看Spring Docs

这就是神奇的地方:所有@Configuration类在启动时都使用CGLIB进行了子类化。在子类中,子方法在调用父方法并创建新实例之前,首先检查容器中是否有任何缓存(作用域)的bean。

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

@Beans 的默认范围是SINGLETON,如果您指定其他范围,例如PROTOTYPE调用将传递给原始方法。

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

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


是否可以覆盖以此方式创建的bean?例如,我有一个Spring定义的类,该类直接调用Bean创建方法。我想要的是不使用由该方法创建的bean,而是由我定义自己的bean(通过使用@Bean和对其进行注释@Primary)。
Fons

4
但是我还记得代理(jdk或CGLIB,无论哪个)不能在自调用中起作用,所以@Configuration如何定义Bean间的依赖关系?它使用的是完全自我调用
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. 在这种情况下,CGLIB创建@Configuration类的子类并覆盖其方法(包括@Bean方法)。因此,当我们从另一个方法调用@Bean方法时,实际上是调用它的替代版本(由于Java动态绑定)。
Flame239 '18

因此,@Component如果我使用CHLIB代替Java Poxy创建代理,则selfInvocation AOP 将起作用吗?
Antoniossss
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.