专栏首页关忆北.客观留步,您真的会使用@Component+@Bean注解(配置类)吗?

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

由此及彼

我在写如何在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

@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

@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

    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());
    }
输出
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

@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

@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中不会因为这个报错而启动失败。

输出
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,以避免奇奇怪怪的问题。

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!
本文分享自作者个人站点/博客:https://blog.csdn.net/weixin_42313773复制
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • 如何在Spring中优雅的使用单例模式?

    单例模式私有化了构造方法,所以其他类无法使用通过new的方式去创建对象,在其他类使用该类的实例时,只能通过getInstance去获取。但是可以通过Constr...

    关忆北.
  • ProGuard 在 Android 上的使用姿势

    Android 开发者
  • Spring的Xml和JavaConfig 扩展你选哪一个?

    上一篇文章我们有怎么介绍到如何通过XML的形式来定义Spring的扩展《Spring面试高频题如何:自定义XML schema 扩展》,好多人都在吐槽现在都什么...

    java金融
  • 【小家Spring】Spring中@PropertySource和@ImportResource的区别,以及各自的实现原理解析

    @PropertySource和@ImportResource或许很多人都用过,并且都还没有用错。但是若真把他俩拿过来一起的时候,却有点傻傻分不清楚了。

    YourBatman
  • Kubernetes 是否值得学习吗?

    Original image by Myriam Zilles from Pixabay

    YP小站
  • Java 程序员都需要懂的 反射!

    今天来简单写一下Java的反射。本来没打算写反射这个知识点的,只是不少的读者都问过我:“你的知识点好像缺了反射阿。能不能补一下?”

    Java3y
  • 拦截控件点击 - 巧用ASM处理防抖

    我在链家网从事Android开发已经三年了,一直致力于优质APP的开发与探索,有时候会写一些小工具,但更多时候是用技术帮助业务增长。我们有专业的测试团队,我尝试...

    小鄧子
  • Hilt 介绍 | MAD Skills

    本文是 MAD Skills 系列 中有关 Hilt 的第一篇文章!在本文中,我们将探讨依赖项注入 (DI) 对应用的重要性,以及 Jetpack 推荐的 An...

    Android 开发者
  • 源码分析:小菜鸟的硬菜

    最近,有朋友和我聊,如何看源码,不知道怎么看,自己看过Spring源码,可是看到后面就被劝退了,觉得太难了。

    田维常
  • 2020[最全]-SpringBoot讲解(最优雅-最精美-最详细)

    11 编写controller运行就好了 访问 localhost:8080//hello

    CaesarChang张旭
  • Spring认证中国教育管理中心-Apache Geode 的 Spring 数据教程十四

    原标题:Spring认证中国教育管理中心-Apache Geode 的 Spring 数据教程十四(Spring中国教育管理中心)

    IT胶囊
  • Why Spring Boot

    本文介绍将各种Spring的配置方式,帮助您了解配置Spring应用的复杂性。 Spring是一个非常受欢迎的Java框架,它用于构建web和企业应用。不像许多...

    程序猿DD
  • lombok踩坑记

    今天中午正在带着耳机遨游在代码的世界里,被运营在群里@了,气冲冲的反问我最近有删生产的用户数据的吗?我肯定客气的回答道没有呀?生产的数据我怎么能随随便便可以删除...

    java金融
  • Spring Cloud 使用 Nacos 进行服务注册发现

    上一篇我们实现了Spring Cloud从nacos server 远端拉取并加载配置。今天我将给大家介绍nacos的另一个重要功能服务注册与发现。服务注册与发...

    码农小胖哥
  • Spring Boot 到底是怎么运行的,你知道吗?

    Spring Boot方式的项目开发已经逐步成为Java应用开发领域的主流框架,它不仅可以方便地创建生产级的Spring应用程序,还能轻松地通过一些注解配置与目...

    纯洁的微笑
  • Spring实战——无需一行xml配置实现自动化注入

      已经想不起来上一次买技术相关的书是什么时候了,一直以来都习惯性的下载一份电子档看看。显然,如果不是基于强烈的需求或强大的动力鞭策下,大部分的书籍也都只是蜻蜓...

    JackieZheng
  • 注解的那些事儿(一)| 为什么要使用注解?

    注解是 JDK 1.5 引入的功能,相信不少开发者都使用过这个功能,但关于为什么要使用注解,你了解过多少呢?

    陈树义
  • 有网友说:2020年还不懂Spring就放弃Java吧?

    Spring这个词对于开发者想必不会陌生,可能你每天都在使用Spring,享受着Spring生态提供的服务,理所当然的用着SpringIOC和SpringAOP...

    程序员追风

扫码关注腾讯云开发者

领取腾讯云代金券