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.rhkb.cn/news/274913.html

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

相关文章

【论文阅读】

4. Analysis of Large-Scale Multi-Tenant GPU Clusters for DNN Training Workloads 出处:2019 USENIX-TAC 大规模多租户GPU集群对DNN训练工作负载的分析 主要工作:描述了Microsoft中一个多租户GPU集群两个月的工作负载特征,研究影响多租户…

iPhone, Android 手机是如何收到推送通知的?

本文转自 公众号 ByteByteGo,如有侵权,请联系,立即删除 iPhone, Android 手机是如何收到推送通知的? 我们的手机或电脑是如何收到推送通知的? 通常我们可以使用消息解决方案 Firebase 来支持通知推送。下图显示了 Fi…

Unity URP 如何写基础的曲面细分着色器

左边是默认Cube在网格模式下经过曲面细分的结果,右边是原状态。 曲面细分着色器在顶点着色器、几何着色器之后,像素着色器之前。 它的作用时根据配置信息生成额外的顶点以切割原本的面片。 关于这部分有一个详细的英文教程,感兴趣可以看一…

HCIP —— BGP 的社团属性

目录 BGP 的社团属性 1.0X00000000 --- internet 2.0XFFFFFF02 --- no - advertise 3.0XFFFFFF01 --- no - export 4.0XFFFFFF03 --- no-export-subconfed 配置: 第一步:使用路由策略执行对流量打上社团属性 第二步:在对等体通告路由之…

【目标检测经典算法】R-CNN、Fast R-CNN和Faster R-CNN详解系列二:Fast R-CNN图文详解

RCNN算法详解:【目标检测经典算法】R-CNN、Fast R-CNN和Faster R-CNN详解系列一:R-CNN图文详解 学习视频:Faster RCNN理论合集 Fast RCNN 概念辨析 1. RoI 在Fast R-CNN中,RoI(Region of Interest,感兴…

【数据可视化】动手用matplotlib绘制关联规则网络图

下载文中数据、代码、绘图结果 文章目录 关于数据绘图函数完整可运行的代码运行结果 关于数据 如果想知道本文的关联规则数据是怎么来的,请阅读这篇文章 绘图函数 Python中似乎没有很方便的绘制网络图的函数。 下面是本人自行实现的绘图函数,如果想…

零、自然语言处理开篇

目录 0、NLP任务的基础——符号向量化 0.0 词袋模型 0.1 查表/One-hot编码 0.2 词嵌入模型/预训练模型 0.2.0 Word2Vec (0)CBOW (1)Skip-gram 0.2.1 GloVe 0.2.2 WordPiece 0.2.3 BERT 0.2.4 ERNIE NLP学习笔记系列&am…

OKHttpRetrofit

完成一个get请求 1.导入依赖 implementation("com.squareup.okhttp3:okhttp:3.14.")2.开启viewBinding android.buildFeatures.viewBinding true 3.加网络权限 和 http明文请求允许配置文件 <?xml version"1.0" encoding"utf-8"?> &l…

利用国产库libhv动手写一个web_server界面(一)

目录 一.实现要求 流程图 测试libhv中的http服务 1.启动http服务端 2.启动http客户端 3.网址访问 4.状态图 5.时序图 结果展示 1.基本的登录界面 2.简易的配置ip及其端口的界面 3.设置成功后返回 这是一个关于webserver HTTP SERVER http server 模块的制作 一.实…

力扣串题:验证回文串2

整体思路&#xff1a;先找到可能存在问题的点&#xff0c;然后判断&#xff0c;如果一切正常则左指针会来到字符串中部 bool isValidPalindrome(char *s, int i, int j) {while (i < j) {if (s[i] ! s[j]) {return false;}i;j--;}return true; }bool validPalindrome(char …

11.Java---语法总结之一个小项目

图书管理系统 Java学习了很久了,今天将运用之前学习的所有东西整理做个小小的小项目. 1.首先是各种包和操作方法建好 2.然后是项目的大框架搭好 3.然后就开始实现各个部分了 看看最后的运行结果吧! 管理员测试 1.登录&显示图书的运行结果 2.查找&新增图书的运行结…

2024年视频号带货蓝海项目真的可做吗?

在数字经济的浪潮下&#xff0c;视频号带货作为一种新兴的电商模式&#xff0c;近年来备受瞩目。随着5G技术的普及和移动设备的更新换代&#xff0c;视频平台用户规模持续增长&#xff0c;为视频号带货提供了广阔的舞台。然而&#xff0c;面对2024年这个未来节点&#xff0c;我…

9个免费游戏后端平台

在这篇文章中&#xff0c;您将看到 九个免费的游戏服务平台提供商&#xff0c;这可以帮助您开始在线多人游戏&#xff0c;而无需预先投入大量资金。 每个提供商都有非常独特的功能&#xff0c;因此成本应该只是决定时要考虑的方面之一。 我还从低预算项目的角度对免费提供商进…

《JAVA与模式》之原型模式

系列文章目录 文章目录 系列文章目录前言一、原型模式的结构二、简单形式的原型模式三、登记形式的原型模式四、克隆满足的条件五、浅克隆和深克隆前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用…

初识kubernetes

Kubernetes核心概念 Master Master节点主要负责资源调度(Scheduler)&#xff0c;控制副本(Replication Controller)&#xff0c;和提供统一访问集群的入口(API Server)。---核心节点也是管理节点 Node Node是Kubernetes集群架构中运行Pod的服务节点&#xff08;亦叫agent或min…

北京碳中和经营许可证办理条件及流程与我们的专业服务

各位老板好&#xff0c;随着全球气候变化问题的日益严重&#xff0c;碳中和成为了企业社会责任和可持续发展的关键一环。在北京&#xff0c;越来越多的企业开始关注并投入到碳中和的行列中。为了规范市场秩序&#xff0c;确保碳中和活动的合法性和有效性&#xff0c;北京地区实…

Splitpanes拆分窗格插件使用

目录 基本用法 纵向排列 遍历渲染 动态拆分宽度 项目开发中用到了拆分窗格(就是下面的效果&#xff0c;可以拆分网页&#xff0c;我们项目通常都是用左右两块拆分&#xff0c;可以通过拖动图标进行左右拖动)&#xff0c;于是就发现了一个很好用的插件&#xff1a;Splitpane…

Day37:安全开发-JavaEE应用JNDI注入RMI服务LDAP服务JDK绕过调用链类

目录 JNDI注入-RMI&LDAP服务 JNDI远程调用-JNDI-Injection JNDI远程调用-marshalsec JNDI-Injection & marshalsec 实现原理 JNDI注入-FastJson漏洞结合 JNDI注入-JDK高版本注入绕过 思维导图 Java知识点&#xff1a; 功能&#xff1a;数据库操作&#xff0c;文…

一款好用的AI工具——边界AICHAT(三)

目录 3.23、文档生成PPT演示3.24、AI文档翻译3.25、AI翻译3.26、论文模式3.27、文章批改3.28、文章纠正3.29、写作助手3.30、文言文翻译3.31、日报周报月报生成器3.32、OCR-DOC办公文档识别3.33、AI真人语音合成3.34、录音音频总结3.35、域方模型市场3.36、模型创建3.37、社区交…

每日汇评:如果支撑位守住2145美元,黄金可能反弹至纪录高位

金价在周二因美国CPI数据火爆而暴跌后保持稳定&#xff1b; 美元和美债收益率在美元/日元下跌中暂停反弹&#xff1b; 随着美国CPI的出炉&#xff0c;市场焦点转向周四的零售销售和PPI数据&#xff1b; 金价在2160美元附近盘整&#xff0c;周二从2195美元的纪录高位回调约1%。由…