首页IT科技springboot相关依赖(Spring IOC官方文档学习笔记(三)之依赖项)

springboot相关依赖(Spring IOC官方文档学习笔记(三)之依赖项)

时间2025-08-05 15:31:53分类IT科技浏览6541
导读:1.依赖注入...

1.依赖注入

(1) 依赖注入(DI)的概念:某个bean的依赖项                ,由容器来负责注入维护                    ,而非我们自己手动去维护        ,以此来达到bean之间解耦的目的            ,如下

//情况一:不使用依赖注入 public class A {} public class B { //B依赖了A对象                    ,这种依赖关系是由我们自己手动来维护的           ,编码于代码之中        ,是强依赖 private A a = new A(); } //情况二:使用依赖注入 @Component public class A {} @Component public class B { //B依赖了A对象                     ,这个A对象是由容器来提供的              ,无需我们关心 @Autowired private A a; }

(2) 依赖注入的两种方式

基于构造函数的依赖注入:容器通过调用带有参数的构造函数来完成依赖项的注入    ,其中构造函数中的每个参数都代表一个依赖项                      ,其参数解析规则如下 //例一: //ExampleA继承自ExampleB public class ExampleA extends ExampleB {} public class ExampleB {} public class Combine { //Combine依赖了ExampleA和ExampleB public Combine(ExampleA a, ExampleB b) { } } <!-- xml配置文件 --> <beans ...> <bean id="exampleA" class="cn.example.spring.boke.ExampleA"></bean> <bean id="exampleB" class="cn.example.spring.boke.ExampleB"></bean> <bean id="combine" class="cn.example.spring.boke.Combine"> <!-- Spring会按照类型进行精确匹配                 ,因此1会被注入到构造函数的第二个参数b中,而2会被注入到构造函数的第一个参数a中                   ,此时与这些构造函数标签声明的先后顺序无关 --> <constructor-arg ref="exampleB"></constructor-arg> <!-- 1 --> <constructor-arg ref="exampleA"></constructor-arg> <!-- 2 --> </bean> </beans> //例二: //将Combine构造函数变更一下 public class Combine { //构造函数参数均为ExampleB public Combine(ExampleB b1, ExampleB b2) { } } <!-- xml配置文件 --> <bean id="combine" class="cn.example.spring.boke.Combine"> <!-- 此时无法进行精确匹配                    ,因为构造函数参数均为ExampleB    ,这时就会按照这些构造函数标签声明的先后顺序进行依赖项的注入                , 结果为1会被注入到构造函数的第一个参数b1中                    ,而2会被注入到构造函数的第二个参数b2中        ,如果将这两个构造函数标签的声明顺序颠倒一下            ,结果也会随之相反 --> <constructor-arg ref="exampleB"></constructor-arg> <!-- 1 --> <constructor-arg ref="exampleA"></constructor-arg> <!-- 2 --> </bean> //例三 public class ExampleC { public ExampleC(int number, String str) { } } <!-- xml配置文件1 --> <beans ...> <bean id="c" class="cn.example.spring.boke.ExampleC"> <!-- 此时的Spring无法判断2000或50000究竟是一个int还是一个String                    ,因此它首先会采取例二中的办法           ,按构造函数标签的声明顺序进行注入        ,结果为number被注入2000                     ,str被注入字符串50000 --> <constructor-arg value="2000"></constructor-arg> <constructor-arg value="50000"></constructor-arg> </bean> </beans> <!-- xml配置文件2 --> <beans ...> <bean id="c" class="cn.example.spring.boke.ExampleC"> <!-- 可以使用type属性              ,指定希望注入的参数的类型    ,来解决歧义问题                      ,结果number被注入50000                 ,str被注入字符串2000,但是如果构造函数参数列表中有多个类型相同的参数                   ,则又会按照构造函数标签的声明顺序进行注入 --> <constructor-arg type="java.lang.String" value="2000"></constructor-arg> <constructor-arg type="int" value="50000"></constructor-arg> </bean> </beans> <!-- xml配置文件3 --> <bean id="c" class="cn.example.spring.boke.ExampleC"> <!-- 使用index属性                    ,按构造函数参数索引位置进行注入    ,index属性为0的构造函数标签的值会被注入到构造函数的第一个参数                ,以此类推 --> <constructor-arg index="1" value="50000"></constructor-arg> <constructor-arg index="0" value="2000"></constructor-arg> </bean> <!-- xml配置文件4 --> <bean id="c" class="cn.example.spring.boke.ExampleC"> <!-- 使用name属性                    ,按照构造函数参数名称进行注入        ,不过要注意            ,Spring要求使用这种方式时必须开启debug flag或结合@ConstructorProperties注解一起使用                    ,详见官方文档(此处存疑           ,因为在我本地可直接使用下面这种方式        ,无需其他配置) --> <constructor-arg name="str" value="50000"></constructor-arg> <constructor-arg name="number" value="2000"></constructor-arg> </bean> 基于setter方法的依赖注入:在实例化bean之后                     ,容器会调用setter方法来注入依赖项 public class ExampleA {} public class ExampleC { private ExampleA exampleA; //使用setter方法注入依赖项exampleA public void setExampleA(ExampleA exampleA) { this.exampleA = exampleA; } } <!-- 方法一:使用自动装配(autowire)              ,即容器自动去寻找依赖项来进行注入 --> <beans ...> <!-- 被依赖项exampleA --> <bean id="exampleA" class="cn.example.spring.boke.ExampleA"></bean> <!-- 注意    ,在基于xml的配置中                      ,如要使用基于setter的自动装配                 ,则要指定autowire属性为byName或byType,如果不指定                   ,则autowire属性默认为no                    ,即不进行依赖注入 --> <bean id="exampleC" class="cn.example.spring.boke.ExampleC" autowire="byType"></bean> </beans> <!-- 方法二:使用手动装配 --> <beans ...> <bean id="exampleA" class="cn.example.spring.boke.ExampleA"></bean> <bean id="exampleC" class="cn.example.spring.boke.ExampleC"> <!-- 使用property标签手动注入    ,name即属性名称                ,ref代表注入对象 --> <property name="exampleA" ref="exampleA"></property> </bean> </beans>

(3) 在依赖注入过程中                    ,Spring会结合PropertyEditor一起使用        ,来将属性从一种类型转换为另一种类型            ,我们也可以利用PropertyEditor进行数据类型转换工作

(4) Spring对依赖项的解析规则:

创建ApplicationContext                    ,并填充bean的配置元数据 bean与bean之间的依赖关系蕴含于成员变量           ,构造函数参数等之中        ,当一个bean被创建时                     ,它的依赖项会被提供 每个成员变量值或构造函数参数值要么是我们所提供的值              ,要么是对容器中另一个bean的引用 Spring会对成员变量值或构造参数值进行确切的类型转换    ,以得到实际的类型                      ,比如 <constructor-arg value="2000" ... 中的值2000                 ,Spring会根据实际情况将其转换为字符串2000或int值2000

(5) Spring在容器创建完成后便会对bean的配置元数据进行检验(此时不会进行依赖项的注入,直到bean被成功创建后才会进行注入)                。单例bean在默认情况下会被提前实例化(即在容器被创建后创建)                   ,而其他作用域的bean只有在需要的时候才会被创建(懒加载)                    。在实际创建bean时                    ,Spring会尽可能晚设置该bean的属性值和依赖项    ,因此Spring容器可能在创建的时候正常但在之后的使用中会产生异常

(6) 在不存在循环依赖的情况下                ,bean A如果有一个依赖项为bean B                    ,则Spring容器会在调用bean A的setBeanB方法来注入bean B之前会完全配置好bean B        ,即Bean B的依赖项已被完全注入            ,其生命周期回调也已被执行                    ,如下

/** * 提供三个类           ,ExampleA        ,ExampleB和ExampleC                     ,其中ExampleA依赖了ExampleB              ,而ExampleC又依赖了ExampleA    ,即B->A->C * 此时                      ,容器会先配置好ExampleB                 ,再注入给ExampleA,而ExampleA配置完毕后                   ,最后会被注入给ExampleC                    ,可观察控制台打印语句的输出顺序 */ public class ExampleB { public ExampleB() { System.out.println("ExampleB构造器..."); } } public class ExampleA { public ExampleA() { System.out.println("ExampleA构造器..."); } private ExampleB exampleB; public void setExampleB(ExampleB exampleB) { System.out.println("ExampleA设置了" + exampleB); this.exampleB = exampleB; } } public class ExampleC { public ExampleC() { System.out.println("ExampleC构造器..."); } private ExampleA exampleA; public void setExampleA(ExampleA exampleA) { System.out.println("ExampleC设置了" + exampleA); this.exampleA = exampleA; } } <!-- xml配置文件 --> <beans ...> <bean id="exampleC" class="cn.example.spring.boke.ExampleC"> <property name="exampleA" ref="exampleA"></property> </bean> <bean id="exampleA" class="cn.example.spring.boke.ExampleA"> <property name="exampleB" ref="exampleB"></property> </bean> <bean id="exampleB" class="cn.example.spring.boke.ExampleB"></bean> </beans>

未完待续...

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
python的plt(python中Plotly Express是什么?)