前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >客观留步,您真的会使用@Component+@Bean注解(配置类)吗?

客观留步,您真的会使用@Component+@Bean注解(配置类)吗?

作者头像
关忆北.
发布2021-01-18 10:31:18
1.3K0
发布2021-01-18 10:31:18
举报
文章被收录于专栏:关忆北.关忆北.
由此及彼

我在写如何在Spring中优雅的使用单例模式?一文的时候有使用到@Component(“xxx”)注解,总所周知,该注解可以将普通的Java类实例化到Spring容器中,可以替代Spring 4.0 版本之前xml配置,xxx就等同于xml中的bean标签的id(所以需要保证唯一),不知道大家有没有了解过Spring配置类的Full模式和Lite模式?如果您第一次听到这个概念,您不妨花费几分钟往下读一读,或许可以让您少掉几根秀发。

详细介绍

Full模式、Lite模式是针对于Spring的配置“类”而言的,xml配置不能与之相提并论,大家都是知道,@Configuration+@Bean注解可以扫描到方法级别的配置,但是为什么不使用@Configuration注解也可以扫描到配置呢?Spring 5.2(SpringBoot 2.0)之后,在使用@Component的类中@Bean注解声明的方法上,或者只使用@Bean注解声明的方法都被称为是配置的Lite模式,而使用@Configuration声明的类+@Bean声明的方法被称为Full模式。具有以下特点的配置都被称为Lite模式:

  • 类上标注有@Component注解
  • 类上标注有@ComponentScan注解
  • 类上标注有@Import注解
  • 类上标注有@ImportResource注解
  • 若类上没有任何注解,但类内存在@Bean方法
  • 标注有@Configuration(proxyBeanMethods = false)

@Configuration注解中,proxyBeanMethods 默认(不写)是true,自Spring 5.2开始,几乎所有内置的@Configuration配置类都使用了proxyBeanMethods = false,具体原因是:

  1. proxyBeanMethods 为true时,需要使用到CGlib动态代理,CGLib将继承用到了极致,CGLib动态代理是代理类去继承目标类,然后重写其中目标类的方法,反之,如果不使用CGlib动态代理,就不用生成CGLib的子类,从而提高运行速度。
  2. 既然proxyBeanMethods 为true的时候,该类被声明为配置类,反之,proxyBeanMethods 为false的时候,就可以将Lite模式的配置类视为普通类,所以使用@Bean注解的方法,可以当成普通方法,可以使用private、final、static修饰符。

Lite模式的缺点:各个Bean之间不能通过方法互相调用

此时就体现了Full模式的优点:Full模式的配置类在Spring容器中是其本身,保证在运行时单例,在多次使用时,都是一个实例

talk is cheaper,show me your code.
Full模式:

Teacher.java

代码语言:javascript
复制
@Accessors(chain = true)
@Data
public class Teacher {
    private String tName;

    private int tAge;

    public Teacher() {
        System.out.println("teacher create current INSTANCE is : " + this.hashCode());
    }
}

TeaWebConfig.java

代码语言:javascript
复制
@Configuration
public class TeaWebConfig {

    @Bean
    public Teacher teacher() {
        return new Teacher();
    }

    @Bean
    public String equalsTeacher(Teacher teacher) {
        System.out.println("invoke others Bean's INSTANCE is "+teacher.hashCode());
        //使用teacher()模拟不同Bean之间的调用
        System.out.println("invoke Constructor's INSTANCE is "+teacher().hashCode());
        return "万物基于MIUI";
    }
}

Test.java

代码语言:javascript
复制
    public static void main(String[] args) {
        ApplicationContext teaContext = new AnnotationConfigApplicationContext(TeaWebConfig.class);
        Teacher teacher = teaContext.getBean(Teacher.class);
        System.out.println("Test.invoke + : " + teacher.hashCode());
    }
输出
代码语言:javascript
复制
teacher create current INSTANCE is : 6018
invoke others Bean's INSTANCE is 6018
invoke Constructor's INSTANCE is 6018
Test.invoke + : 6018

可以看到,Full模式下,配置类对象在Spring中是单例。

Lite模式

User.java

代码语言:javascript
复制
@Accessors(chain = true)
@Data
public class User {

    private int age;

    private String name;

    private String doHomeWork;

    public User() {
        System.out.println("user create current INSTANCE is : " + this.hashCode());
    }
}

userConfig.class

代码语言:javascript
复制
@Component
public class StuWebConfig {
    @Bean
    public User user() {
        return new User();
    }

    @Bean
    public String name(User user) {
        System.out.println(user.hashCode());
        //使用user()模拟不同Bean之间的调用
        System.out.println(user().hashCode());
        return "万物基于MIUI";
    }
}

如果是在IDEA下,在System.out.println(user().hashCode());这行会有错误提醒: Method annotated with @Bean is called directly. Use dependency injection instead. 表示:未添加@Configuration注解,导致@Bean之间相互调用出错。 当然,我们会把实验继续下去,实际在本demo中不会因为这个报错而启动失败。

输出
代码语言:javascript
复制
user create current INSTANCE is : 45326
invoke others Bean's INSTANCE is 207959
user create current INSTANCE is : 23423
invoke Constructor Bean's INSTANCE is 207959

Lite模式使用配置类时,多次调用时会创建多个对象,并不是单例模式

所以,为了您的秀发:

建议使用Full模式, @Configuration+@Bean,以避免奇奇怪怪的问题。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-12-05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 由此及彼
  • 详细介绍
  • talk is cheaper,show me your code.
    • Full模式:
      • 输出
    • Lite模式
      • 输出
  • 所以,为了您的秀发:
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档