SpringBoot this调用@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内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 为什么说要慎用SpringBoot @ComponentScan

    目录 场景复现 解密 解决方案 场景复现 为了统一定制一个过滤器(Filter),所以在另外一个工程里面创建了一个过滤器,并通过jar包的方法导入当前项目,通过@ComponentScan({"org.example.config"})指定扫描包路径. 下面的我的启动类: 导入的jar: 问题 预期效果是这样,正常加载 启动后,原来的Swagger目录进去是这样的,原来的Controller全部都没有被加载进来 解密 以为过滤器导致所有路径没有加载,后面百度了解BasicErrorCo

  • SpringBoot在容器中创建实例@Component和@bean有什么区别

    目录 @Component和@Bean的区别 @Component和@Bean注解在容器中创建实例区别 @Component和@Bean的区别 在Spring Boot中,@Component注解和@Bean注解都可以用于创建bean.它们的主要区别在于它们的作用范围和创建方式. @Component注解是一种通用的注解,可以用于标注任何类.被标注的类将被Spring容器自动扫描并创建为一个bean.这个bean的名称将默认为类名的首字母小写,除非使用@Qualifier注解进行更改.@Comp

  • SpringBoot @Configuration与@Bean注解使用介绍

    目录 demo示例 特点和特性 之前我们都是通过xml的方式定义bean,里面会写很多bean元素,然后spring启动的时候,就会读取bean xml配置文件,然后解析这些配置,然后会将这些bean注册到spring容器中,供使用者使用. Spring3.0开始,@Configuration用于定义配置类,定义的配置类可以替换xml文件,一般和@Bean注解联合使用. @Configuration注解可以加在类上,让这个类的功能等同于一个bean xml配置文件. @Bean注解类似于bean

  • Springboot项目实现将类从@ComponentScan中排除

    目录 将类从@ComponentScan中排除 问题描述 方案一 方案二 方案三 方案四 @ComponentScan 详解 将类从@ComponentScan中排除 问题描述 最近在学习SpringCloud的Ribbon,在使用 @RibbonClient(name = "SPRINGCLOUD-P-DEPT", configuration = RibbonConfig.class) 为服务指定负载均衡策略的时候,根据Ribbon官方文档介绍,自定义的Ribbon配置类不允许被Sp

  • SpringBoot中@ComponentScan的使用详解

    目录 SpringBoot @ComponentScan的使用 SpringBoot @ComponentScan 作用 SpringBoot @ComponentScan的使用 SpringBoot的启动类中有一个@ComponentScan,之前项目由于这个注解造成打包失败,这里对于这个注解进行总结,防止下次遇到这个问题再被难住. 其实这个注解主要是针对于第三方jar包中注解的应用. 如果第三方包中没有使用注解那么就完全不需要使用这个注解 使用方式如图所示,这里扫描的是 maven项目的依赖

  • SpringBoot解决@Component无法注入其他Bean的问题

    目录 SpringBoot @Component无法注入其他Bean 一.现象 二.解决 三.代码如下 @Component注解自动注入失效问题 SpringBoot @Component无法注入其他Bean 一.现象 在SpringBoot新new一个普通类,习惯性添加@Component让Spring扫描. 在@Component修饰的类里注入了其他Bean,运行时提示注入的为null 但这个Bean可以在控制层被引入,在普通类就不行. 二.解决 找了些资料,最后也没解决注入的问题. 最后的

  • SpringBoot this调用@Bean效果详解

    目录 思考的起源 查找信息 更远一步 在一个@Bean方法内,this调用同一个类的@Bean方法会有什么效果呢? 思考的起源 首先上代码: public class BeanOne { } public class BeanTwo { public BeanTwo(BeanOne beanOne){ } } @Configuration public class BeanConfigTest { @Bean @ConditionalOnMissingBean public BeanOne be

  • springboot配置内存数据库H2教程详解

    业务背景:因soa系统要供外网访问,处于安全考虑用springboot做了个前置模块,用来转发外网调用的请求和soa返回的应答.其中外网的请求接口地址在DB2数据库中对应专门的一张表来维护,要是springboot直接访问数据库,还要专门申请权限等,比较麻烦,而一张表用内置的H2数据库维护也比较简单,就可以作为替代的办法. 环境:springboot+maven3.3+jdk1.7 1.springboot的Maven工程结构 说明一下,resource下的templates文件夹没啥用.我忘记

  • SpringBoot整合Shiro的代码详解

    shiro是一个权限框架,具体的使用可以查看其官网 http://shiro.apache.org/  它提供了很方便的权限认证和登录的功能. 而springboot作为一个开源框架,必然提供了和shiro整合的功能!接下来就用springboot结合springmvc,mybatis,整合shiro完成对于用户登录的判定和权限的验证. 1.准备数据库表结构 这里主要涉及到五张表:用户表,角色表(用户所拥有的角色),权限表(角色所涉及到的权限),用户-角色表(用户和角色是多对多的),角色-权限表

  • springboot项目配置swagger2示例详解

    swagger简介 Swagger是一款RESTful接口的文档在线自动生成.功能测试功能框架.一个规范和完整的框架,用于生成.描述.调用和可视化RESTful风格的Web服务,加上swagger-ui,可以有很好的呈现. 当我们在后台的接口修改了后,swagger可以实现自动的更新,而不需要人为的维护这个接口进行测试. 一.swagger2中常用的注解作用 注解 作用 @Api 修饰整个类,描述Controller的作用 ,表示标识这个类是swagger的资源 @ApiOperation 描述

  • SpringBoot中@Autowired生效方式详解

    目录 前言 正文 注册AutowiredProcessor的BeanDefinition 实例化AutowiredProcessor 创建bean时进行注入 后记 前言 @Component public class SimpleBean3 { @Autowired private SimpleBean simpleBean; } @Autowired修饰的字段会被容器自动注入.那么Spring Boot中使如何实现这一功能呢? AutowiredAnnotationBeanPostProces

  • Springboot @Configuration与自动配置详解

    不知道大家第一次搭SpringBoot环境的时候,有没有觉得非常简单.无须各种的配置文件,无须各种繁杂的pom坐标,一个main方法,就能run起来了.与其他框架整合也贼方便,使用EnableXXXXX注解就可以搞起来了! 所以今天来讲讲SpringBoot是如何实现自动配置的~ @SpringBootApplication: Spring Boot应用标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot需要运行这个类的main方法来启动SpringBoot应用: 先看

  • SpringBoot整合rockerMQ消息队列详解

    目录 Springboot整合RockerMQ 使用总结 消费模式 生产者组和消费者组 生产者投递消息的三种方式 如何保证消息不丢失 顺序消息 分布式事务 Springboot整合RockerMQ 1.maven依赖 <dependencies> <!-- springboot-web组件 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>

  • SpringBoot 自动装配的原理详解分析

    目录 前言 自动装配案例 自动装配分析 自动装配总结 前言 关于 ​​SpringBoot​​​ 的自动装配功能,相信是每一个 ​​Java​​ 程序员天天都会用到的一个功能,但是它究竟是如何实现的呢?今天阿粉来带大家看一下. 自动装配案例 首先我们通过一个案例来看一下自动装配的效果,创建一个 ​​SpringBoot​​ 的项目,在 ​​pom​​ 文件中加入下面的依赖. <dependency> <groupId>org.springframework.boot</gro

  • SpringBoot集成quartz实现定时任务详解

    目录 准备知识点 什么是Quartz Quartz的体系结构 什么是Quartz持久化 实现案例 - 单实例方式 实现案例 - 分布式方式 后端实现 前端实现 测试效果 准备知识点 需要了解常用的Quartz框架. 什么是Quartz 来源百度百科, 官网地址:http://www.quartz-scheduler.org/ Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用.Quartz可以用来

  • Springboot实现动态定时任务流程详解

    目录 一.静态 二.动态 1.基本代码 2.方案详解 2.1 初始化 2.2 单次执行 2.3 停止任务 2.4 启用任务 三.小结 一.静态 静态的定时任务可以直接使用注解@Scheduled,并在启动类上配置@EnableScheduling即可 @PostMapping("/list/test1") @Async @Scheduled(cron = "0 * * * * ?") public void test1() throws Exception { Ob

随机推荐