• Spring中@Bean标注的方法是如何创建对象呢?


    在这里插入图片描述
    在这里插入图片描述

    博主 默语带您 Go to New World.
    个人主页—— 默语 的博客👦🏻
    《java 面试题大全》
    🍩惟余辈才疏学浅,临摹之作或有不妥之处,还请读者海涵指正。☕🍭
    《MYSQL从入门到精通》数据库是开发者必会基础之一~
    🪁 吾期望此文有资助于尔,即使粗浅难及深广,亦备添少许微薄之助。苟未尽善尽美,敬请批评指正,以资改进。!💻⌨

    Spring中@Bean标注的方法是如何创建对象呢?

    摘要

    在本文中,我们将深入探讨Spring框架中使用@Bean标注的方法是如何创建对象的。我们将通过分析源码和实际案例演示,揭示Spring是如何通过FactoryMethod机制实现Bean的创建和管理的。此外,我们还会详细研究了@Bean标注方法中的参数注入过程,包括对同类型Bean的决策过程和使用@Primary注解的情况。

    引言

    在Spring框架中,@Bean注解是定义bean的一种方式,但背后的实现原理很多开发者可能并不清楚。本文旨在揭示@Bean标注的方法是如何被Spring创建成Bean的,以及其中涉及的源码细节。

    Spring中的@Bean标注

    创建Bean的过程

    在一个典型的Spring配置类中,使用@Bean标注的方法会被Spring容器识别为Bean的创建方法。通过分析源码,我们发现Spring会为这些方法生成一个FactoryMethod,并通过执行该方法来创建Bean对象。让我们通过一个简单的配置类来演示这个过程:

    @Configuration
    public class MyConfiguration {
    
        @Bean
        public Blue blue() {
            System.out.println("创建 Blue 对象");
            return new Blue();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    上述代码中,blue()方法被标注为@Bean,最终通过执行FactoryMethod来创建Blue对象。这一过程将在后续源码分析中展开讨论。


    在一个典型的Spring配置类中,使用@Bean标注的方法会被Spring容器识别为Bean的创建方法。通过分析源码,我们发现Spring会为这些方法生成一个FactoryMethod,并通过执行该方法来创建Bean对象。让我们通过一个简单的配置类来演示这个过程:

    @Configuration
    public class AppConfig {
    
        @Bean
        public MyBean myBean() {
            return new MyBean();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这个例子中,myBean方法使用了@Bean注解,告诉Spring容器需要调用这个方法来创建一个Bean对象。接下来,让我们通过源码分析一下Spring是如何处理这个配置类的。

    1. @Configuration注解的处理: 首先,Spring会检测到AppConfig类上标注了@Configuration注解,表示这是一个配置类,Spring会为该类创建一个CGLIB代理。这个代理类将用于拦截@Bean方法的调用,以便进行一些额外的处理。
    2. 处理@Bean方法: 当应用程序上下文启动时,Spring容器会扫描配置类,找到所有标注了@Bean的方法。对于每个@Bean方法,Spring会生成一个MethodInterceptor,该拦截器负责处理@Bean方法的调用。这个拦截器将被注册到CGLIB代理中。
    3. FactoryMethod的生成: 当应用程序需要获取MyBean时,实际上是通过调用CGLIB代理的myBean方法。该方法的执行会触发拦截器,拦截器会调用原始的myBean方法,并将其返回的对象作为Bean。
    4. Bean的生命周期管理: 如果MyBean类上有其他的生命周期注解(如@PostConstruct@PreDestroy),Spring容器会相应地处理这些生命周期方法。

    总体来说,@Bean方法的执行过程经历了CGLIB代理、拦截器调用、原始方法执行等步骤,最终完成了Bean的创建和注入过程。这使得Spring框架能够实现很多高级特性,比如AOP(面向切面编程)和动态代理。

    参数注入流程

    在实际应用中,@Bean标注的方法可能包含参数,我们需要深入了解这些参数是如何被注入的。


    在Spring中,@Bean标注的方法可以包含参数,而这些参数可以通过不同的方式进行注入。让我们深入了解这些参数注入的流程:

    考虑以下的示例:

    @Configuration
    public class AppConfig {
    
        @Bean
        public MyBean myBean(AnotherBean anotherBean) {
            return new MyBean(anotherBean);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这个例子中,myBean方法接受一个AnotherBean类型的参数。下面是参数注入的流程:

    1. 参数类型匹配: Spring容器会检查所有@Bean方法的参数,尝试查找与参数类型匹配的其他Bean。在这个例子中,Spring会查找容器中是否有一个类型为AnotherBean的Bean。
    2. Bean创建或注入: 如果找到了匹配的Bean,Spring容器将使用该Bean来满足myBean方法的参数。如果容器中没有匹配的Bean,通常会抛出异常,除非该参数允许为null,或者使用@Autowired(required = false)等方式处理。
    3. Bean的创建过程: 如果AnotherBean还没有被创建,那么Spring容器会按照相同的@Bean创建过程(参考前面的回答)来创建AnotherBean。这可能涉及到更多的方法拦截和CGLIB代理。
    4. 方法执行: 一旦所有的依赖关系都解析和注入完成,myBean方法将被调用,创建并返回MyBean实例。这个实例将包含通过参数传递进来的AnotherBean

    总体来说,Spring使用参数类型匹配的方式来解析@Bean方法的参数,然后自动注入相应的Bean。这使得我们能够方便地在@Bean方法中引入其他组件或服务,并利用Spring容器来进行依赖注入。在复杂的应用中,还可以使用@Autowired@Qualifier等注解来更精确地控制注入过程。

    根据参数名注入

    如果@Bean方法存在参数,Spring容器会尝试根据参数名在容器中找到对应的Bean。如果成功找到,就将该Bean注入到方法中。


    在Spring中,通过参数名进行注入是一种便捷的方式。如果@Bean方法存在参数,并且这些参数的名称与容器中的Bean定义的名称一致,Spring容器会尝试根据参数名自动注入相应的Bean。这种方式通常用于简化配置,避免手动指定@Qualifier@Autowired等注解。

    考虑以下的示例:

    @Configuration
    public class AppConfig {
    
        @Bean
        public MyBean myBean(AnotherBean anotherBean) {
            return new MyBean(anotherBean);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这个例子中,myBean方法有一个参数名为anotherBean,而且在容器中存在一个Bean定义的名称也为anotherBean。Spring容器会根据参数名自动将匹配的Bean注入到myBean方法中。

    如果没有找到与参数名匹配的Bean,Spring容器通常会抛出异常,除非该参数允许为null,或者使用@Autowired(required = false)等方式处理。

    这种根据参数名进行注入的方式适用于简单的情况,但在复杂的应用中,尤其是当存在多个相同类型的Bean时,可能需要使用更精确的方式,例如使用@Qualifier注解或者@Autowired结合构造函数来明确指定要注入的Bean。


    1. @Primary注解:
      • 如果有多个同类型的Bean,而且其中一个标注了@Primary注解,那么Spring容器会优先选择标注了@Primary注解的Bean进行注入。
    @Component
    @Primary
    public class PrimaryBean implements MyInterface {
        // ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 实现@Comparator排序接口:
      • 如果没有@Primary注解,Spring容器将尝试比较这些Bean是否实现了Comparator接口。
      • 如果实现了,Spring容器会按照Comparator接口的排序规则选择排序结果的第一个Bean进行注入。
    @Component
    public class BeanA implements MyInterface, Comparator<BeanA> {
        // ...
    }
    
    • 1
    • 2
    • 3
    • 4
    1. 根据入参名称和Bean的beanName进行比较:
      • 如果上述两个条件都不满足,Spring容器会尝试根据入参的名称和Bean的beanName进行比较。
      • 如果找到了与参数名或beanName匹配的Bean,就会将该Bean注入到目标位置。
      • 如果没有找到匹配的Bean,通常会抛出异常,除非该参数允许为null,或者使用@Autowired(required = false)等方式处理。
    @Component("customBeanName")
    public class BeanB implements MyInterface {
        // ...
    }
    
    • 1
    • 2
    • 3
    • 4

    总体来说,Spring容器会尽力按照上述规则选择合适的Bean进行注入。在实际应用中,合理使用@Primary注解、实现Comparator接口或者通过指定beanName等方式,可以更精确地控制同类型Bean的注入行为。


    同类型Bean的决策过程

    如果参数名未能匹配到Bean,Spring会根据参数类型在容器中查找匹配的Bean。但是,如果存在多个同类型的Bean,Spring会进行决策判断:

    • 首先,查看是否有Bean标注了@Primary注解,如果有,则使用该Bean进行注入。
    • 如果没有@Primary注解,Spring会判断这些Bean是否实现了@Comparator排序接口,如果有,将使用排序结果的第一个Bean进行注入。
    • 如果上述两个条件都不满足,Spring将尝试根据入参名称和Bean的beanName进行比较,匹配成功则注入该Bean,否则报错。

    演示参数注入流程

    让我们通过一个实际的配置类演示参数注入流程:

    @Configuration
    public class MyConfiguration {
    
        @Bean
        public Blue blue(White white1) {
            System.out.println("获取了 White 对象:" + white1);
            return new Blue();
        }
    
        @Bean
        @Primary
        public White white1() {
            White white = new White();
            System.out.println("创建的 White1 对象,携带 @Primary 注解:" + white);
            return white;
        }
    
        @Bean
        public White white2() {
            White white = new White();
            System.out.println("创建的 White2 对象:" + white);
            return white;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    上述代码展示了根据入参名称和@Primary注解进行参数注入的情况。我们将通过代码输出详细说明每一步的执行过程。

    总结

    通过本文的深入研究,我们对Spring框架中@Bean标注方法的创建过程和参数注入流程有了更清晰的认识。了解这些底层机制有助于我们更好地理解Spring容器的工作原理,提高在实际项目中使用Spring的技能。

    参考资料

    1. Spring Framework Documentation
    2. Understanding the Spring @Bean Annotation
    3. Spring @Primary Annotation

    希望通过本文的阐述,读者能更深入地了解Spring中@Bean标注方法的内部实现和参数注入机制。

    文末赠书

    在这里插入图片描述

    内容介绍:

    信息安全原理与实践》(第3版)经过全面修订和更新,新增了关于网络安全基础知识的章节,并扩展介绍了跨站脚本(XSS)攻击、Stuxnet和其他恶意软件、SSH协议、安全软件开发和安全协议。书中的新示例说明了RSA密码体系、椭圆曲线加密、SHA-3,以及包括比特币和区块链在内的散列函数的应用。更新后的习题、表和图有助于读者学习经典密码体系、现代对称加密、公钥加密、密码分析、简单认证协议、入侵和恶意软件检测系统、量子计算等实用知识。这本颇受欢迎的教科书涉及的信息安全方法非常实用:

    l 涵盖快速发展的信息安全领域的最新内容。

    l 解释会话密钥、完全正向保密、时间戳、SSH、SSL、IPSec、Kerberos、WEP、GSM和其他认证协议。

    l 解决访问控制技术,包括认证和授权、ACL,以及多级安全和隔离项。

    l 讨论软件安全问题,从恶意软件检测到安全软件开发。

    l 包括教师解决方案手册、PowerPoint幻灯片、讲座视频和其他教学资源。

    购买链接

    🥇 赠书活动规则 📚

    🌟 请关注我的博客,即刻获得更多珍贵的编程和考研资源。

    📲 添加博主Wxx:我的微信号是Solitudemind,添加后即刻获得参与活动的资格。

    💬 **活动参与方法:**在底部留言 "为梦想扬帆!加油!🚀

    🎁 结果揭晓时间:在11月20日,我将从留言中随机抽取3名幸运读者,并将结果公布于评论区和微信朋友圈。

    感谢大家的参与!🚀

    🪁🍁 希望本文能够给您带来一定的帮助🌸文章粗浅,敬请批评指正!🍁🐥

    如对本文内容有任何疑问、建议或意见,请联系作者,作者将尽力回复并改进📓;(联系微信:Solitudemind )

    点击下方名片,加入IT技术核心学习团队。一起探索科技的未来,共同成长。

    在这里插入图片描述

  • 相关阅读:
    独立站新手卖家应注意的要点
    Flutter笔记:关于应用程序中提交图片作为头像
    文件包含漏洞
    python作业
    服务器中间件的种类和日常使用
    飞翔的小鸟
    Javascript知识【案例:重写省市联动&案例:列表左右选择】
    RocketMQ单机环境搭建
    网页表单文本框的自动填写(四种方法)
    图片的谱表征
  • 原文地址:https://blog.csdn.net/qq_42055933/article/details/134338163