SpringBoot this调用@Bean效果详解

 更新时间:2023年02月03日 10:57:40   作者:愿做无知一猿  
这篇文章主要介绍了在一个@Bean方法内,this调用同一个类的@Bean方法会有什么效果,我们可以通过bean的名称、bean的类型或者bean的名称+类型来获取容器中的bean

在一个@Bean方法内,this调用同一个类的@Bean方法会有什么效果呢?

思考的起源

首先上代码:

public class BeanOne { 
}
public class BeanTwo {
    public BeanTwo(BeanOne beanOne){
    }
}
@Configuration
public class BeanConfigTest {
    @Bean
    @ConditionalOnMissingBean
    public BeanOne beanOne() {
        System.err.println("带有@ConditionalOnMissingBean的默认 BeanOne 产生------");
        return new BeanOne();
    }
    @Bean
    public BeanTwo beanTwo() {
        return new BeanTwo(this.beanOne());
    }
}

​ 可以看到上述三个类,其中BeanOne就是一个默认的Bean实现,标注了@ConditionalOnMissingBean代表它可以被覆盖;BeanTwo是一个使用BeanOne的类,类似于注入;BeanConfigTest就是用来注册这俩Bean的,可以看到在BeanTwo这个里面,直接使用了this.beanOne(),我一开始的想法就是,this调用,那始终调用的都是beanOne()这个方法呀,那不就代表着BeanOne不能被覆盖了。

​ 但是,当我将BeanOne加上@Component注解之后,运行程序,会发现,控制台根本没有输出我打印的那句话,那就可以猜测 this.beanOne()其实并不是简单的方法调用方法。

查找信息

阅读@Bean上的注释:

@Bean Methods in @Configuration Classes
Typically, @Bean methods are declared within @Configuration classes. In this case, bean methods may reference other @Bean methods in the same class by calling them directly. This ensures that references between beans are strongly typed and navigable. Such so-called 'inter-bean references' are guaranteed to respect scoping and AOP semantics, just like getBean() lookups would. These are the semantics known from the original 'Spring JavaConfig' project which require CGLIB subclassing of each such configuration class at runtime. As a consequence, @Configuration classes and their factory methods must not be marked as final or private in this mode. For example:
   @Configuration
   public class AppConfig {
       @Bean
       public FooService fooService() {
           return new FooService(fooRepository());
       }
       @Bean
       public FooRepository fooRepository() {
           return new JdbcFooRepository(dataSource());
       }
       // ...
   }

​ 简要概述就是:

Spring会对每个@Configuration标注的类进行CGLIB子类化,在一个Bean内使用方法调用另一个Bean,就像是getBean()查找一样。

​ 从它注释上的描述可以总结出,像this.beanOne()这类方法调用,其实就类似于getBean()去获取一个名叫beanOneBean。那么上面的输出结果就能解释了。

​ 上面这段注释下面,紧跟着一段注释,一起看一下:

@Bean Lite Mode
@Bean methods may also be declared within classes that are not annotated with @Configuration. For example, bean methods may be declared in a @Component class or even in a plain old class. In such cases, a @Bean method will get processed in a so-called 'lite' mode.
Bean methods in lite mode will be treated as plain factory methods by the container (similar to factory-method declarations in XML), with scoping and lifecycle callbacks properly applied. The containing class remains unmodified in this case, and there are no unusual constraints for the containing class or the factory methods.
In contrast to the semantics for bean methods in @Configuration classes, 'inter-bean references' are not supported in lite mode. Instead, when one @Bean-method invokes another @Bean-method in lite mode, the invocation is a standard Java method invocation; Spring does not intercept the invocation via a CGLIB proxy. This is analogous to inter-@Transactional method calls where in proxy mode, Spring does not intercept the invocation — Spring does so only in AspectJ mode.
For example:
   @Component
   public class Calculator {
       public int sum(int a, int b) {
           return a+b;
       }
       @Bean
       public MyBean myBean() {
           return new MyBean();
       }
   }

​ 简要概述就是:

@Component标注的类中,你使用@Bean标注的方法处于一种叫做lite模式下,lite模式中的Bean方法将被容器视为普通工厂方法,lite模式中的Bean,不支持Bean间的相互调用,如果相互调用,那么将会被视为标准的Java方法调用,Spring不会通过CGLIB为当前类生成子类。最后他说,这类似于内部 @Transactional方法调用,在代理模式下,Spring不会拦截调用;但是仅在AspectJ模式下,Spring会拦截调用。好像也是,标注@Transcational的方法是不能直接相互调用的。

​ 那用上面的例子试一下看看,是不是变成了普通Java方法调用了:

@Component
public class BeanOne {
}
public class BeanTwo {
    public BeanTwo(BeanOne beanOne){
    }
}
@Component
//@Configuration
public class BeanConfigTest {
    /**
     * @Bean 创建的默认是单例Bean
     */
    @Bean
    @ConditionalOnMissingBean
    public BeanOne beanOne() {
        System.err.println("带有@ConditionalOnMissingBean的默认 BeanOne 产生------");
        return new BeanOne();
    }
    @Bean
    public BeanTwo beanTwo() {
        return new BeanTwo(this.beanOne());
    }
}

​ 此时BeanOne上标注了@Component,但是打印了输出语句,可见其变成了普通方法调用。

更远一步

Bean的Full和Lite模式

​ 当@Bean方法在没有标注@Configuration注释的类中声明时,它们被称为Lite模式的Bean。例如:在@Component中声明的@Bean方法,甚至只是在一个非常普通的类中声明的Bean方法,都被认为是Lite版的配置类。和Full模式的@Configuration不同,Lite模式的@Bean方法不能声明Bean之间的依赖关系。因此,这样的@Bean方法不应该调用其他@Bean方法。每个这样的方法实际上只是一个特定Bean引用的工厂方法(factory-method),没有任何特殊的运行时语义。

​ 怎么确定一个Bean是不是Lite模式呢?

只要不标识@Configuration(proxyBeanMethods=true)其他都是lite模式。(当然,标注了的就是Full模式啦)

上述例子的spring-context版本是6.0.2,其中@Configuration的属性proxyBeanMethods的默认值是true。

​ 那么proxyBeanMethods为true和false有什么使用上的区别呢?

设置为false此时bean是lite模式:

此时运行时不再需要给对应类生成CGLIB子类,提高了运行性能,降低了启动时间,但是不能声明@Bean之间的依赖,也就是说不能通过方法调用来依赖其它Bean。

设置为true时为Full模式

此时配置类会被CGLIB增强(生成代理对象),放进IoC容器内的是代理,方法相互调用能够保证是同一个实例,都指向IoC内的那个单例,可以支持通过常规Java调用相同类的@Bean方法而保证是容器内的Bean,但是运行时会给该类生成一个CGLIB子类放进容器,有一定的性能、时间开销。

到此这篇关于SpringBoot this调用@Bean效果详解的文章就介绍到这了,更多相关SpringBoot调用@Bean内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot2.x 整合 thumbnailator 图片处理的示例代码

    SpringBoot2.x 整合 thumbnailator 图片处理的示例代码

    这篇文章主要介绍了SpringBoot2.x 之整合 thumbnailator 图片处理,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • 如何利用Java在图片上添加文字水印效果

    如何利用Java在图片上添加文字水印效果

    最近发现经常被别的网站盗用,而且不注明出处,因此不得不加上水印,这篇文章主要给大家介绍了关于如何利用Java在图片上添加文字水印效果的相关资料,需要的朋友可以参考下
    2022-01-01
  • Netty分布式ByteBuf缓冲区分配器源码解析

    Netty分布式ByteBuf缓冲区分配器源码解析

    这篇文章主要为大家介绍了Netty分布式ByteBuf缓冲区分配器源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-03-03
  • 浅谈自定义校验注解ConstraintValidator

    浅谈自定义校验注解ConstraintValidator

    鉴于通用性和普遍性,Spring框架提供了validator组件,通过一些校验器,可以对一些数据进行统一的完整性和有效性等校验,即简单又好用
    2021-06-06
  • Struts2开发环境搭建 附简单登录功能实例

    Struts2开发环境搭建 附简单登录功能实例

    这篇文章主要介绍了Struts2开发环境搭建,为大家分享一个简单登录功能实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-11-11
  • java实现点击按钮弹出新窗体功能

    java实现点击按钮弹出新窗体功能

    这篇文章主要为大家详细介绍了java实现点击按钮弹出新窗体功能,旧窗体不进行操作,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-07-07
  • java设计模式之外观模式(Facade)

    java设计模式之外观模式(Facade)

    这篇文章主要为大家详细介绍了java设计模式之外观模式Facade的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-01-01
  • Java设计模式之Strategy模式

    Java设计模式之Strategy模式

    Strategy模式即策略模式,就是将一个算法的不同实现封装成一个个单独的类,这些类实现同一个接口,使用者直接使用该接口来访问具体的算法。这个样子,使用者就可以使用不同的算法来实现业务逻辑了。
    2016-07-07
  • Hibernate中实现增删改查的步骤详解

    Hibernate中实现增删改查的步骤详解

    本篇文章主要介绍了Hibernate中实现增删改查的步骤与方法,具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • mybatis-plus 新增/修改如何实现自动填充指定字段

    mybatis-plus 新增/修改如何实现自动填充指定字段

    这篇文章主要介绍了mybatis-plus 新增/修改实现自动填充指定字段方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06

最新评论