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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27990060/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 05:25:13  来源:igfitidea点击:

Calling a @Bean annotated method in Spring java configuration

javaspringcglib

提问by markwatson

I'm curious about how spring injection handles calling methods with the @Beanannotation. If I put a @Beanannotation 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 @Beanannotated method to get an instance. My question is, why doesn't this cause there to be multiple instances of the bean floating around?

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

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 BasicAuthenticationEntryPointas 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?

例如,请参阅下面的代码(取自另一个问题)。该entryPoint()方法用 注释@Bean,所以我可以想象 spring 将创建一个BasicAuthenticationEntryPoint作为 bean的新实例。然后,我们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();       
}

采纳答案by wassgren

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

是的,Spring 有一些魔法。检查Spring 文档

This is where the magic comes in: All @Configurationclasses 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.

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

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

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

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

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

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

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

Calls to static @Beanmethods never get intercepted by the container, not even within @Configurationclasses (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 @Beanmethod has standard Java semantics, resulting in an independent instance being returned straight from the factory method itself.

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