目录
什么是Spring IoC依赖注入(反转控制,IoC)?实现IoC依赖注入(3种方式)
Spring IoC
控制反转(Inversion of Control,IoC),也称为依赖注入(Dependency Injection,DI),是面向对象编程中的一种设计理念,用来降低程序代码之间的耦合度。
什么是依赖注入?
Spring的依赖注入指的是应用程序本身不负责对象的创建和维护,应用程序所需要的类在应用加载启动的时候创建完成,并通过setter方法将类直接加载到应用程序中(DI),在Spring容器中并设置类的一系类属性
例如:类的作用域,bean与bean之间的关系,类的模式,在Spring容器中检测,类的生命周期等
IOC(Inversion of Control)依赖注入
指程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部的注入。Spring的依赖注入对调用者和被调用者几乎没有任何要求,完全支持对POJO(简单的Java对象)之间依赖关系的管理
就是把新建对象(new Object())的权利交给Spring容器去管理,需要使用的时候只需到容器中去取就可以、无需去new一个对象
实现依赖注入(3种)
在Spring配置文件中,使用<bean>元素来定义Bean(也称为组件)的实例。这个元素有两个常用属性:
①id:表示定义的Bean实例的名称
②class:表示定义的Bean实例的类型
(1)使用<bean>元素定义一个组件时,通常需要使用id属性为其指定一个用来访问的唯一名称。如果表示定义的Bean指定更多的别名,可以通过name属性指定,名称之间使用逗号、分号或空格进行分隔
(2)Spring为Bean属性赋值通过调用属性的setter方法实现的,这种做法称为“设值注入”,而非直接为属性赋值。若属性名为who,但是setter方法名为setSomebody,Spring配置文件中(<propertes>)应写成name=”somebady”而非name=”who”,所以在为属性和setter访问器命名时,一定要注意遵循JavaBean的命名规范(值注入settter的名字)。
(1)值注入(setter方法注入)
通过类的setter方法完成依赖关系的设置
name属性的取值依setter方法名而定,要求这个类里面这个对应的属性必须有setter方法。
属性注入
(1)属性注入是通过setter方法注入bean的属性值或者依赖对象
(2)属性注入需要使用<property>元素,使用name属性指定bean的属性名称,value属性指定bean的属性的值。甚至可以使用value子节点来进行配置。
属性 | 描述 |
---|---|
id | 区分beans管理下的bean的唯一标识。这个是一个非必须的属性,特定的情况下可以省略 |
name | 指定bean的别名(同alias )。与id相比,name的属性更加灵活可以使用特殊的字符如 ‘ / ’ 还可以通过逗号、空格、冒号分割name |
class | 大部分情况下是必须的,指定bean的数据类型,在抽象模板中可以不需要指定class |
1.Entity类(JavaBean)
public class Human {
private String name;
private String password;
private Map<String,String> map = new HashMap<String,String>();
private Map<String,Book> maps = new HashMap<String,Book>();
//省略getter/setter方法
}
2.Spring XML配置文件
普通属性注入
<bean class="cn.my.beans.Human">
<property name="name" value="one"></property>
<property name="password" value="two"></property>
</bean>
<bean id="one" class="cn.my.beans.Human">
<property name="name" value="one"></property>
<property name="password">
<value>two</value>
</property>
</bean>
Map对象注入
通过Map标签定义,Map标签里面有可以有多个<entry>,必须在key里面定义键String
HashMap<String, String>
<bean id="map" class="cn.my.beans.Human">
<property name="name" value="dada"></property>
<property name="password" value="12313"></property>
<property name="map">
<map>
<entry key="a" value="wqeq"></entry>
<entry key="b" value="qwdqd"></entry>
<entry key="c" value="fwafw"></entry>
</map>
</property>
</bean>
HashMap<String,Book>
<bean id="maps" class="cn.my.beans.Human">
<property name="name" value="dada"></property>
<property name="password" value="12313"></property>
<property name="maps" ref="mm"></property>
</bean>
<util:map id="mm">
<entry key="aa" value-ref="book1"></entry> 引用外部book
<entry key="bb" value-ref="book2"></entry>
<entry key="cc" value-ref="book3"></entry>
</util:map>
<bean id="book1" class="cn.my.beans.Book">
<property name="id" value="dada"></property>
<property name="name" value="12313"></property>
</bean>
(2)构造注入
构造注入指的是在接受注入的类中,定义一个构造方法,并在构造方法的参数中定义需要注入的元素,其中,index表示构造方法中的参数索引(第一个参数索引为0)
通过构造方法注入bean里面的属性或者依赖对象,保证了bean实例在实例化后使用<constructor-arg>
<bean id="" class="">
<constructor-arg index="" value="" type=""/>
</bean>
一个元素表示构造方法的一个参数
使用时不区分顺序。当构造方法的参数出现混淆,无法区分时
<constructor-arg>元素的属性
构造方法参数 | 描述 |
---|---|
index | 指定该参数的位置索引。位置从0开始 |
type | 指定参数的类型。避免字符串和基本数据类型的混淆 |
构造注入的时效性好,在对象实例化时就得到所依赖的对象,便于在对象的初始化方法中使用依赖对象;但受限于方法重载的形式,使用灵活性不足。没有值注入使用灵活,但setter时效性不足,并且大量的setter访问器增加了类的复杂性;Spring并不倾向于某种注入方式.
1.Entity实体类(JavaBean)
public class Human {
private String name;
private String password;
private Map<String, String> map = new HashMap<String, String>();
private Map<String, Book> maps = new HashMap<String, Book>();
public Human(String name, String password) {
this.name = name;
this.password = password;
}
public Human(String name, String password, Map<String, String> map) {
this.name = name;
this.password = password;
this.map = map;
}
}
2.XML
<!-- 构造注入 -->
<bean id="one" class="cn.my.beans.Human">
<constructor-arg value="" index=""></constructor-arg>
<constructor-arg value="" index=""></constructor-arg>
</bean>
<bean id="one" class="cn.my.beans.Human">
<constructor-arg value="" type="java.lang.String"></constructor-arg>
<constructor-arg value="" type="java.lang.Double"></constructor-arg>
<constructor-arg value="" type="java.lang.String"></constructor-arg>
</bean>
(3)工厂方法注入(用的少,不推荐)
Spring框架中的工厂方法注入是一种较少使用的功能,因为它的使用场景有限,并且通常会与Spring的其他部分(如自动装配)冲突。
工厂方法注入用于在Spring容器中创建复杂对象,它不需要直接将实例化逻辑放在组件类中,而是将这些逻辑移到一个或多个工厂类中。
简单示例:
1、创建一个工厂类:
public class ComplexObjectFactory {
public ComplexObject createComplexObject() {
ComplexObject complexObject = new ComplexObject();
// 设置复杂对象的属性或依赖关系
return complexObject;
}
}
2、配置Spring XML文件:
<bean id="complexObjectFactory" class="ComplexObjectFactory"/>
<bean id="complexObject" factory-bean="complexObjectFactory" factory-method="createComplexObject"/>
或者使用Java配置:
@Configuration
public class AppConfig {
@Bean
public ComplexObjectFactory complexObjectFactory() {
return new ComplexObjectFactory();
}
@Bean
public ComplexObject complexObject() {
return complexObjectFactory().createComplexObject();
}
}
在这个例子中,ComplexObject是一个复杂的对象,它的实例化被委托给ComplexObjectFactory。在Spring配置中,我们定义了工厂类的bean和目标bean。目标bean指定了使用工厂方法创建的bean。
虽然这种方法可以用于创建复杂对象,但通常情况下,直接在组件类的@Bean方法中进行设置更加简单和直接。工厂方法注入更适用于需要进行一些复杂逻辑以确定如何创建对象的情况,或者当需要共享对象创建代码时。但在大多数情况下,使用@Component和自动装配是更好的选择。