Spring之注入模型

前言

之前我写过一篇关于BeanDefinition的文章,讲述了各个属性的作用,其中有一个属性我没有提到,因为这个属性比较重要,所以这里单独开一篇文章来说明

上一篇博文链接Spring之BeanDefinitionicon-default.png?t=N7T8https://blog.csdn.net/qq_38257958/article/details/134823169?spm=1001.2014.3001.5501

再探AbstractBeanDefinition源码

通过源码我们得出结论,注入类型有四种

  • AUTOWIRE_NO (0)
  • AUTOWIRE_BY_NAME (1)
  • AUTOWIRE_BY_TYPE (2)
  • AUTOWIRE_CONSTRUCTOR (3)

PS : 实际有五种,AUTOWIRE_AUTODETECT已过期,我们暂不讨论

默认情况下的注入模型

代码准备

创建配置类AppConfig

package com.test.model.config;import org.springframework.context.annotation.ComponentScan;@ComponentScan("com.test.model")
public class AppConfig {}

创建一个普通bean

package com.test.model.component;import org.springframework.stereotype.Component;@Component
public class MixComponent {}

创建一个BeanFactoryPostProcessor(后面简称bfpp) 

package com.test.model.bfpp;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;@Component
public class AutowireBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) registry.getBeanDefinition("mixComponent");int autowireMode = beanDefinition.getAutowireMode();System.out.println(autowireMode);}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}

创建启动类

package com.test.model;import com.test.model.config.AppConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class Main {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);}
}

运行main方法,查看运行结果 

 结论 : 默认的注入模型是0 (AUTOWIRE_NO)

默认情况下的依赖注入

创建三个普通bean

@Component
public class ComponentA {
}@Component
public class ComponentB {
}@Component
public class ComponentC {
}

依赖注入

package com.test.model.component;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class MixComponent {@Autowiredprivate ComponentA componentA;private ComponentB componentB;private ComponentC componentC;@Autowiredpublic void setComponentB(ComponentB componentB) {this.componentB = componentB;}public MixComponent() {}@Autowiredpublic MixComponent(ComponentC componentC) {this.componentC = componentC;}
}

默认情况下的依赖注入的三种方式

  • 属性注入
  • setter注入
  • 构造器注入

运行main方法,查看运行结果

 byName情况下的依赖注入

通过bfpp修改注入模型

package com.test.model.bfpp;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;@Component
public class AutowireBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) registry.getBeanDefinition("mixComponent");// 将注入模型改为byNamebeanDefinition.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}

改造MixComponent 

package com.test.model.component;import org.springframework.stereotype.Component;@Component
public class MixComponent {// 没有Autowired注解private ComponentA componentA;// 没有Autowired注解private ComponentB componentB;// 没有Autowired注解private ComponentC componentC;public void setComponentA(ComponentA componentA) {this.componentA = componentA;}public void setComponentB(ComponentB componentB) {this.componentB = componentB;}public void setComponentC(ComponentC componentC) {this.componentC = componentC;}
}

 运行main方法,查看运行结果

源码解析

AbstractAutowireCapableBeanFactory#populateBean

AbstractAutowireCapableBeanFactory#autowireByName

AbstractAutowireCapableBeanFactory#unsatisfiedNonSimpleProperties

 unsatisfiedNonSimpleProperties方法大概分为两个步骤

  1. 利用Spring的自省机制获取pds
  2. 判断这个pd是否符合条件
    1. 判断pd是否存在writeMethod
    2. 判断pd的propertyType是不是需要忽略的类
    3. pvs是否已存在相同name的值
    4. propertyType是不是普通类

我来解释一下pd需要满足的四个条件

条件1
package com.test.model.component;import org.springframework.stereotype.Component;@Component
public class Demo1 {public Object getAbc() {return null;}public void setAbc(Object abc) {}public Object getXyz() {return null;}public void setXyz(Object xyz) {}
}

不管我们是不是真实存在abc、xyz这样的属性,只要类中存在setXxx或者getXxx这样的方法,我们就认为类中存在一个名称为xxx的属性

PS : 我测试了一下,setXxx方法只能存在一个参数

条件2

比如bean实现了xxxAware接口,其相应的实现方法会被过滤掉

相关源码

AbstractApplicationContext#prepareBeanFactory

PS : 可能还有其他地方也添加了相关接口,debug的时候不止这几个

条件3
package com.test.model.bfpp;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;@Component
public class Demo1FactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {AbstractBeanDefinition b2 = (AbstractBeanDefinition) registry.getBeanDefinition("demo1");b2.getPropertyValues().add("abc", new Object());}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}

我们可以手动给指定bean的属性设置值,那样就不会在Spring容器中查找符合条件的bean了。

条件4

Spring定义的普通类

byType情况下的依赖注入

byType和byName类似 主要就是根据参数类型从Spring中查找符合条件的bean,主要关注unsatisfiedNonSimpleProperties方法

测试发现一个有意思的情况,下方代码在byName的情况下会错,在byType的情况下会正确注入

package com.test.model.component;import org.springframework.stereotype.Component;@Component
public class Demo2 {private ComponentC componentC;public void setComponentA(ComponentC componentC) {this.componentC = componentC;}
}

构造器注入

相关源码AbstractAutowireCapableBeanFactory#createBeanInstance

构造器注入并非只有注入模型是AUTOWIRE_CONSTRUCTOR才会执行构造器注入的逻辑,另外三个条件如果满足其一也会执行构造器注入,这里我用代码演示其他三种情况

具体细节可以看我之前写的博文Spring之推断构造方法icon-default.png?t=N7T8https://blog.csdn.net/qq_38257958/article/details/134957631?spm=1001.2014.3001.5501

ctors != null的几种情况
package com.test.model.component;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class Demo3 {/*** case1:有且仅有一个有参构造方法*/private ComponentA componentA;public Demo3(ComponentA componentA) {this.componentA = componentA;}/*** case2:有且仅有一个@Autowired(required = true)标注的构造方法*/private ComponentB componentB;private ComponentC componentC;@Autowired(required = true)public Demo3(ComponentB componentB) {this.componentB = componentB;}public Demo3(ComponentC componentC) {this.componentC = componentC;}/*** case3:有多个@Autowired(required = false)标注的构造方法*/@Autowired(required = false)public Demo3(ComponentB componentB) {this.componentB = componentB;}@Autowired(required = false)public Demo3(ComponentC componentC) {this.componentC = componentC;}
}
mbd.hasConstructorArgumentValues()
package com.test.model.component;import org.springframework.stereotype.Component;@Component
public class Demo4 {private ComponentB componentB;private ComponentC componentC;public Demo4(ComponentB componentB) {this.componentB = componentB;}public Demo4(ComponentC componentC) {this.componentC = componentC;}
}
package com.test.model.bfpp;import com.test.model.component.ComponentB;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;@Component
public class Demo4FactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) registry.getBeanDefinition("demo4");// 指定构造器Demo4(ComponentB componentB)beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,new ComponentB());}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}
 !ObjectUtils.isEmpty(args)
package com.test.model.component;import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;@Component
@Lazy
public class Demo5 {private ComponentB componentB;private ComponentC componentC;public Demo5(ComponentB componentB) {this.componentB = componentB;}public Demo5(ComponentC componentC) {this.componentC = componentC;}
}

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

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

相关文章

【Datawhale学习笔记】从大模型到AgentScope

从大模型到AgentScope AgentScope是一款全新的Multi-Agent框架,专为应用开发者打造,旨在提供高易用、高可靠的编程体验! 高易用:AgentScope支持纯Python编程,提供多种语法工具实现灵活的应用流程编排,内置…

pc端vue2项目使用uniapp组件

项目示例下载 运行实例: 这是我在pc端做移动端底代码时的需求,只能在vue2使用,vue3暂时不知道怎么兼容。 安装依赖包时可能会报:npm install Failed to set up Chromium r756035! Set “PUPPETEER_SKIP_DOWNLOAD” env variable …

数据治理实践——金融行业大数据治理的方向与实践

目录 一、证券数据治理服务化背景 1.1 金融数据治理发展趋势 1.2 证券行业数据治理建设背景 1.3 证券行业数据治理目标 1.4 证券行业数据治理痛点 二、证券数据治理服务化实践 2.1 国信证券数据治理建设框架 2.2 国信证券数据治理建设思路 2.3 数据模型管理 2.4 数据…

ChatGPT+MATLAB应用

MatGPT是一个由chatGPT类支持的MATLAB应用程序,由官方Toshiaki Takeuchi开发,允许您轻松访问OpenAI提供的chatGPT API。作为官方发布的内容,可靠性较高,而且也是完全免费开源的,全程自己配置,无需注册码或用…

SpecAugment: A Simple Data Augmentation Method for Automatic Speech Recognition

摘要 我们提出了SpecAugment,这是一种用于语音识别的简单数据增强方法。SpecAugment直接应用于神经网络的特征输入(即滤波器组系数)。增强策略包括对特征进行变形、遮蔽频道块和遮蔽时间步块。我们在端到端语音识别任务中将SpecAugment应用于…

【SQL】601. 体育馆的人流量(with as 临时表;id减去row_number()思路)

前述 知识点学习: with as 和临时表的使用12、关于临时表和with as子查询部分 题目描述 leetcode题目:601. 体育馆的人流量 思路 关键:如何确定id是连续的三行或更多行记录 方法一: 多次连表,筛选查询方法二&…

vulhub中Weblogic SSRF漏洞复现

Weblogic中存在一个SSRF漏洞,利用该漏洞可以发送任意HTTP请求,进而攻击内网中redis、fastcgi等脆弱组件。 访问http://your-ip:7001/uddiexplorer/,无需登录即可查看uddiexplorer应用。 SSRF漏洞测试 SSRF漏洞存在于http://your-ip:7001/ud…

Python分支结构

我们刚开始写的Python代码都是一条一条语句顺序执行,这种代码结构通常称之为顺序结构。 然而仅有顺序结构并不能解决所有的问题,比如我们设计一个游戏,游戏第一关的通关条件是玩家在一分钟内跑完全程,那么在完成本局游戏后&#x…

js实现导出/下载excel文件

js实现导出/下载excel文件 // response 为导出接口返回数据,如上图 const exportExcel (response, fileName:string) >{const blob new Blob([response.data], {type: response.headers[content-type] //使用获取的excel格式});const downloadElement documen…

mysql5.6---windows和linux安装教程和忘记密码怎么办

一、windows安装 1.完成解压 解压完成之后将其放到你喜欢的地址当中去,这里我默认放在了D盘,这是我的根目录 2.配置环境变量 我的电脑->属性->高级->环境变量->系统变量 选择PATH,在其后面添加: (注意自己的安装地址) D:\mysql-5.6.49…

数据结构:图的存储与遍历(待续)

图(Graph)是一种较线性表和树更为复杂的非线性结构。在图结构中,对结点(图中常称为顶点)的前驱和后继个数不加限制, 即结点之间的关系是任意的。 一、基本概念和一般结论 因为一条边关联两个顶点&#xff0…

12---风扇电路设计

视频链接 风扇硬件电路设计01_哔哩哔哩_bilibili 风扇电路设计 1、风扇简介 电脑风扇又称为散热风扇,一般用于散热。提供给散热器和机箱使用。市面上一般的散热风扇尺寸大小由直径2.5cm到30cm都有,厚度由6mm到76mm都有,而根据不同运作要求…

抽样算法——【数据科学与工程算法基础】

一、前言 这是课程的第二章节——抽样算法,主要分为三类。 详情可参考: 数据科学的算法基础——学习记录跳转中心 二、正篇 1.系统抽样 课本只介绍了最简单的——等距抽样。 直线等距抽样(Nn*k):即总体个数可以被抽…

JAVA实战开源项目:学生日常行为评分管理系统(Vue+SpringBoot)

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、系统设计2.1 功能模块设计2.2.1 登录注册模块2.2.2 用户管理模块2.2.3 评分项目模块2.2.4 评分数据模块2.2.5 数据字典模块 2.3 可行性设计2.4 用例设计2.5 数据库设计2.5.1 整体 E-R 图2.5.2 用户2.5.3 评分项目2.5.4 评分数据2.5.…

弹性盒子布局 Flexbox Layout

可以嵌套下去 1.display 属性 默认行排列 <style>.flex-item{ height: 20px;width: 10px;background-color: #f1f1f1;margin: 10px;}</style> </head> <body> <div class"flex-container"><div class"flex-item">1&l…

功能测试转自动化测试好不好转型?

手工测试做了好多年&#xff0c;点点点成了每天必须做的事情。但是随着自动化测试趋势的日渐明显&#xff0c;以及受到薪资、技能的双重考验&#xff0c;掌握自动化测试成为了必备技能。 手工转自动化测试&#xff0c;不是一蹴而就的。“预先善其事&#xff0c;必先利其器”&a…

C++:2024/3/11

作业1&#xff1a;编程 要求&#xff1a;提示并输入一个字符串&#xff0c;统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数 代码&#xff1a; #include <iostream>using namespace std;int main() {string str;cout << "请输入一个字…

linux查看文件内容cat,less,vi,vim

学习记录 目录 catlessvi vim cat 输出 FILE 文件的全部内容 $ cat [OPTION] FILE示例 输出 file.txt 的全部内容 $ cat file.txt查看 file1.txt 与 file2.txt 连接后的内容 $ cat file1.txt file2.txt为什么名字叫 cat&#xff1f; 当然和猫咪没有关系。 cat 这里是 co…

一款功率电子开关TP6062

一、基本概述 The TP606X is a low voltage,single P-MOSFET high-side power switch, optimized for self-powered and bus-powered Universal Serial Bus (USB) applications. This switch operates with inputs ranging from 2.4V to 5.5V, making it ideal for both 3V a…

封装方法3-2

八大数据类型一次只能代表一个&#xff0c;所以不能作为返回值&#xff0c; 数组可以做为返回值&#xff0c;把excel的内容2行11列当作数组&#xff0c;存在二维数据里 处理ecxel-22个单元值的返回结果写什么&#xff1f; 1、认识二维数组是什么&#xff1f; 数 组&#xff…