高级Spring之BeanFactory的实现

news2024/11/14 22:39:49

            Spring 的发展历史较为悠久,因此很多资料还在讲解它较旧的实现,这里出于怀旧的原因,把它们都列出来,供大家参考

  • DefaultListableBeanFactory,是 BeanFactory 最重要的实现,像控制反转依赖注入功能,都是它来实现

  • ClassPathXmlApplicationContext,从类路径查找 XML 配置文件,创建容器(旧)

  • FileSystemXmlApplicationContext,从磁盘路径查找 XML 配置文件,创建容器(旧)

  • XmlWebApplicationContext,传统 SSM 整合时,基于 XML 配置文件的容器(旧)

  • AnnotationConfigWebApplicationContext,传统 SSM 整合时,基于 java 配置类的容器(旧)

  • AnnotationConfigApplicationContext,Spring boot 中非 web 环境容器(新)

  • AnnotationConfigServletWebServerApplicationContext,Spring boot 中 servlet web 环境容器(新)

  • AnnotationConfigReactiveWebServerApplicationContext,Spring boot 中 reactive web 环境容器(新)

另外要注意的是,后面这些带有 ApplicationContext 的类都是 ApplicationContext 接口的实现,但它们是组合了 DefaultListableBeanFactory 的功能,并非继承而来

         在这里,我们以BeanFactory 最重要的实现DefaultListableBeanFactory为例,来讲解BeanFactory的实现:  

  //创建实例对象
   DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

      因为刚创建好的对象是没有任何bean的,所以我们要进行添加bean,准备三个基本的Config类,用来添加bean

  @Configuration
    static class Config {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }

        @Bean
        public Bean3 bean3() {
            return new Bean3();
        }

        @Bean
        public Bean4 bean4() {
            return new Bean4();
        }
    }
  static class Bean1 {
        private static final Logger log = LoggerFactory.getLogger(Bean1.class);

        public Bean1() {
            log.debug("构造 Bean1()");
        }

        @Autowired
        private Bean2 bean2;

        public Bean2 getBean2() {
            return bean2;
        }
  static class Bean2 {
        private static final Logger log = LoggerFactory.getLogger(Bean2.class);

        public Bean2() {
            log.debug("构造 Bean2()");
        }
    }

   创建config的beanDefinition,用来加入bean工厂里,以后有bean工厂来进行管理

    AbstractBeanDefinition beanDefinition =
                BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();

注册beanDefinition 

    beanFactory.registerBeanDefinition("config", beanDefinition);

        ok,bean工厂里面就有了一个叫config的bean,单例模式。

测试一波,来看看这个bean工厂里面有多少个beanDefinition 

   for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);//Config
        }

        看到这里,我们可能会有个疑问,因为在配置类中,我们不是加了@Bean的注解吗?所以容器应该有bean1和bean2,但输出的结果却只有config,为什么呢? 

        输出结果就说明这个@Configuration,@Bean注解没有被解析,也就是这个BeanFactory它缺少了解析这些注解的能力,功能并不完整。

        那么我们怎么才能让它的功能完整,可以解析这些注解呢? 有其他的类来提供解析这些注解的能力

   //给BeanFactory 添加一些常用的后处理器
     AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

     这些后处理器就是对beanFactory进行功能上的扩展,解决不能解析注解的问题。

     此时,我们再来输出结果一波:

   for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }

     多了一些spring内置的bean后处理器,第一个是用来处理@Configuration注解,将其配置类里面的定义的bean信息补充到beanFactory中

     这个时候,输出的结果并没有bean1和bean2,这是为什么呢?那是因为我们这是添加了后处理器,但并没有让它运行

  // BeanFactory 后处理器主要功能,补充了一些 bean 定义
        // bean 的定义(class, scope, 初始化, 销毁) 
  //解析 @Configuration @Bean注解
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
          //执行BeanFactory的后处理器
        beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });

    ok,此刻我们看到输出结果有bean1和bean2,؏؏☝ᖗ乛◡乛ᖘ☝؏؏ 

   我们将bean1和bean2添加到bean工厂里了,那么可不可以拿出来用呢?我们来试试看:

 System.out.println(beanFactory.getBean(Bean1.class).getBean2());

     bean1可以拿到,但是bean2等于null,这是为什么呢?@Autowired依赖注入没有被解析。

    这也是bean工厂的扩展功能,是由其他的后处理器通过的解析功能,用ben的后处理器来完成实现,来,看代码:

     // Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
                //获取比较器(单例)
                .sorted(beanFactory.getDependencyComparator())
                .forEach(beanPostProcessor -> {
            System.out.println(">>>>" + beanPostProcessor);
          //建立bean工厂与后处理器的联系
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        });

       ok,؏؏☝ᖗ乛◡乛ᖘ☝؏؏

bean的后处理器有多个,功能不同,解析的注解也不同,来看源代码:

 

 bean 后处理器会有排序的逻辑,来看排序规则:

     System.out.println("Common:" + (Ordered.LOWEST_PRECEDENCE - 3));// 2147483644
        System.out.println("Autowired:" + (Ordered.LOWEST_PRECEDENCE - 2));// 2147483645

     所以common排在前面,Autowired排在后面。

总结:

         beanFactory 不会做的事 :  

                  1. 不会主动调用 BeanFactory 后处理器
                   2. 不会主动添加 Bean 后处理器
                   3. 不会主动初始化单例
                   4. 不会解析beanFactory 还不会解析 ${ } 与 #{ }

         bean 后处理器会有排序的逻辑

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/175867.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

十六进制转八进制+超大数据处理(蓝桥杯基础练习C/C++)

目录 1 题目要求 2 代码 2.1 以十进制为媒介(不可行) 2.2 以二进制为媒介 3 可能会遇到的难点 4 结论 5 延伸 5.1 超大数据阶乘 5.2 超大数据加法 5.3 以十进制为媒介的进制转换 1 题目要求 2 代码 2.1 以十进制为媒介&#xf…

【LeetCode】一文吃透回溯算法(附例题)

回溯 DFS 算法深入浅出,一文吃透! 原文同步在:https://github.com/EricPengShuai/Interview/blob/main/algorithm/回溯算法.md 回溯算法 主要参考的是 liweiwei 的总结 0. 概念 回溯法 采用试错的思想,它尝试分步的去解决一个问题…

MATLAB | 如何使用MATLAB绘制韦恩图的高阶版本:upset图

韦恩图随着阶数升高会越来越复杂,当阶数达到7或者以上时几乎没办法绘制: 但是使用upset图却可以比较轻易的绘制: 两种类型图的对应关系: 这期便教大家如何绘制这样的upset图: 教程部分 0 数据准备 数据需要的是0,1矩…

SQL注入现象

package com.bjpowernode.jdbc;import java.sql.*; import java.util.HashMap; import java.util.Map; import java.util.ResourceBundle; import java.util.Scanner; /*** 如果输入的用户名和密码是下面这样的,就会发生非注册人员登录的情况,叫做SQL注入…

【Java|golang】2287. 重排字符形成目标字符串

给你两个下标从 0 开始的字符串 s 和 target 。你可以从 s 取出一些字符并将其重排,得到若干新的字符串。 从 s 中取出字符并重新排列,返回可以形成 target 的 最大 副本数。 示例 1: 输入:s “ilovecodingonleetcode”, targ…

go tool pprof与trace的简单使用

pprof pprof是Google的程序采样分析工具,其使用分为,采样和分析。Go 语言内置了pprof。 Go 语言库中有两种方式使用pprof,一种是通过net/http/pprof库,另一种是通过runtime/pprof库。 net/http/pprof的简单使用 引入 _ "n…

【计算机网络】HTTP/HTTPS

HTTP网络协议 虽然我们说, 应用层协议是我们程序猿自己定的. 但实际上, 已经有大佬们定义了一些现成的, 又非常好用的应用层协议, 供我们直接参考使用. HTTP(超文本传输协议)就是其中之一 理解网络协议 协议是一种 “约定”. socket api的接口, 在读写数据时, 都是按 “字符…

零基础学MySQL(三)-- 对表中数据的增删改【新年快乐】

目录✨一、INSERT 语句(添加表中数据)1.基本语法2.应用案例3.使用细节🎆二、UPDATE 语句(修改表中数据)1.基本语法2.应用案例3.使用细节🎇三、DELETE 语句(删除表中数据)1.基本语法2…

【手写 Vue2.x 源码】第三十七篇 - 组件部分 - 组件的合并

一,前言 上篇,介绍了 Vue.extend 实现,主要涉及以下几个点: Vue.extend 简介;Vue.extend 实现,包括:组件初始化;子类继承父类;修复 constructor 指向问题; …

基于ssm jsp在线教育系统源码

演示视频: 基于ssm jsp在线教育系统源码范围 系统主要目标设计 随着互联网发展,在线教学成为一种支持知识共享,无距离知识交流的一种方式,我们的系统主要完成在线视频观看,在线教学,在线知识交流&#xff0…

虚幻引擎中CityEngine导入资产的自动化替换

在这篇博文中,我们将学习将 ArcGIS CityEngine Datasmith 场景导入虚幻引擎后替换资产的流程。 替换工作流由虚幻引擎的数据资产(可以认为是简单的表格数据)控制。 一旦设置正确,这些数据资产就可以在项目之间共享。 推荐&#x…

This old-style function definition is not preceded by a prototype

文章目录Introwarning 及解决 截屏知其然,却不知其所以然Intro 在 Xcode 14 中随意写了几个C命令行程序,编译运行OK。 但是有以下两种报错: This old-style function definition is not preceded by a prototype This function declaration…

联诚发携手电影《流浪地球2》,让电影特效和场景全面升级!

一万五千年前,一根愈合的人类股骨,标志着人类文明的诞生;一万五千年后,当太阳系将不复存在,人类的团结与勇气将延续文明的火种!新年第一部精彩绝伦的国产科幻大片,大家期待已久的《流浪地球2》终…

动态规划的优化

动态规划的优化 一、空间优化 说明 动态规划空间优化为滚动数组优化,即对于一个多维数组,转移时均是由上一阶段转移来的,则可以将这一维省略,以降低空间复杂度,但要注意转移时的顺序; 例题 0 - 1 背包…

基础算法--背包问题(01背包问题、完全背包问题、多重背包问题、分组背包问题)

文章目录前言01背包问题完全背包问题多重背包问题分组背包问题前言 背包问题:给我们 i 件物品,每件物品都有体积 vi 和权重 wi ,给我们限制条件,让我们选择在背包的容量内,物品达到权重最大 01背包问题 01背包问题描…

KK集团再冲刺港交所上市:期内被罚款30万元,曾存在“二清”问题

时隔一年,KK集团再次在港交所递交上市申请。2023年1月20日,KK集团(KK Group Company Holdings Limited)向港交所提交上市申请。据贝多财经了解,KK集团曾于2021年11月4日在港交所递表,后已“失效”。 相较于…

LeetCode_单周赛_329

2544. 交替数字和 代码1 转成字符串&#xff0c;逐个判断 class Solution {public int alternateDigitSum(int n) {char[] s ("" n).toCharArray();int t 1;int ans 0;for (int i 0; i < s.length; i) {ans (s[i] - 0) * t;t -t;}return ans;} }代码2 一…

国内做SaaS软件的知名企业有哪些?

SaaS厂商还挺多挺杂的。具体要列举的话&#xff0c;还是按照分类来吧。 通用业务和垂直行业的SaaS 对使用方来说&#xff0c;一般分为业务通用型和垂直行业型。 通用型是可以服务所有企业的&#xff0c;比如CRM&#xff08;客户管理软件&#xff09;、HR软件、协同办公软件&a…

linux系统中利用QT实现语音识别项目的操作方法

大家好&#xff0c;今天主要和大家分享一下&#xff0c;如何使用linux系统上的语音识别项目的操作方法与实现。 目录 第一&#xff1a;语音识别基本简介 第二&#xff1a;语音识别产品申请账号 第三&#xff1a;具体代码实现 第一&#xff1a;语音识别基本简介 AI音箱对传统…

Java_Git:3. 远程仓库

目录 1 添加远程库 1.1 在github上创建仓库 1.2 ssh协议 1.2.1 什么是ssh? 1.2.2 基于密匙的安全验证 1.2.3 ssh密钥生成 ​​​​​​​​​​​​​​1.2.4 ssh密钥配置 1.3 同步到远程仓库 1.3.1 使用git bash 1.3.2 使用TortoiseGit同步 2 从远程仓库克隆 2.1 …