1、IoC容器概述
IoC 全称为 Inversion of Control
,翻译为 “控制反转”,它还有一个别名为 DI(Dependency Injection
),即依赖注入。
所谓 IOC ,就是由 Spring IOC 容器来负责对象的生命周期和对象之间的关系
该org.springframework.context.ApplicationContext
接口代表Spring IoC容器,并负责实例化,配置和组装Bean。
容器通过读取配置元数据来获取有关要实例化,配置和组装哪些对象的指令。
配置元数据以 XML ,Java批注 或 Java代码 表示。
它使您能够表达组成应用程序的对象以及这些对象之间的丰富相互依赖关系。
2、如何理解“控制反转”呢
理解好它的关键在于我们需要回答如下四个问题:
- 谁控制谁:在传统的开发模式下,我们都是采用直接 new 一个对象的方式来创建对象,也就是说你依赖的对象直接由你自己控制,但是有了 IOC 容器后,则直接由 IoC 容器来控制。所以“谁控制谁”,当然是 IoC 容器控制对象。
- 控制什么:控制对象。
- 为何是反转:没有 IoC 的时候我们都是在自己对象中主动去创建被依赖的对象,这是正转。但是有了 IoC 后,所依赖的对象直接由 IoC 容器创建后注入到被注入的对象中,依赖的对象由原来的主动获取变成被动接受,所以是反转。
- 哪些方面反转了:所依赖对象的获取被反转了。
3、bean总览
3.1 命名方式
一共有三种,可以通过id、name还有外部通过<alias name="bean" alias="aliasName">标签命名。
每个bean具有一个或多个标识符。这些标识符在承载Bean的容器内必须唯一。一个bean通常只有一个标识符。
3.2 实例化方式
构造方法实例化;
<!--构造方法实例化--> <bean id="teacher" class="com.doubleh.pojo.Teacher"> <constructor-arg name="id" value="1"></constructor-arg> <constructor-arg name="name" value="李白"></constructor-arg> </bean>
静态工厂方法实例化;
<!--静态工厂方法实例化:构造方法私有化用,例如单例类--> <!-- public class Teacher{ private static Teacher teacher = new Teacher(); private Teacher() { } public static Teacher createInstance() { return teacher; } } --> <bean id="teacher" class="com.doubleh.pojo.Teacher" factory-method="createInstance"> </bean>
实例工厂方法实例化(暂未发现用处);
<!--实例工厂方法实例化--> <!-- public class DefaultServiceLocator { private static Teacher teacher = new Teacher(); private Teacher() { } public Teacher createInstance() { return teacher; } } --> <bean id="dsl" class="com.doubleh.pojo.DefaultServiceLocator"> </bean> <bean id="createInstance" factory-bean="dsl" factory-method="createInstance"></bean>
4、bean依赖注入方式
4.1 构造器注入
顾名思义就是被注入的对象通过在其构造方法中声明依赖对象的参数列表,让外部知道它需要哪些依赖对象。
//老师类 public class Teacher { private int id; private String name; public Teacher(int id, String name) { this.id = id; this.name = name; } @Override public String toString() { return "Teacher{" + "id=" + id + ", name='" + name + '\'' + '}'; } } //学生类 public class Student { private int id; private String name; private Teacher teacher; public Student(int id, String name, Teacher teacher) { this.id = id; this.name = name; this.teacher = teacher; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", teacher=" + teacher + '}'; } }
<!--配置Teacher类--> <bean id="teacher" class="com.doubleh.pojo.Teacher"> <constructor-arg index="0" value="1"></constructor-arg> <constructor-arg index="1" value="屈原"></constructor-arg> </bean> <!--配置学生类--> <bean class="com.doubleh.pojo.Student" id="student" > <!--构造方法注入:根据参数下标赋值--> <constructor-arg index="0" value="1"></constructor-arg> <!--根据参数名赋值:推荐--> <constructor-arg name="name" value="李白"></constructor-arg> <!--根据数据类型赋值--> <constructor-arg type="com.doubleh.pojo.Teacher" ref="teacher"></constructor-arg> </bean>
构造方法通过<constructor-arg>标签来注入,分别可以通过以下三种方式注入值:
参数下标(index)注入;
参数名(name)注入,推荐这种;
参数类型(name)注入;
4.2 setter注入
对于 JavaBean 对象而言,我们一般都是通过 getter 和 setter 方法来访问和设置对象的属性。所以,当前对象只需要为其所依赖的对象提供相对应的 setter 方法,就可以通过该方法将相应的依赖对象设置到被注入对象中。这种也比较灵活。
setter注入前提是JavaBean对象必须由setter方法,否则会报:
org.springframework.beans.NotWritablePropertyException:
Invalid property 'id' of bean class [com.doubleh.pojo.Student]:
Bean property 'id' is not writable or has an invalid setter method.
Does the parameter type of the setter match the return type of the getter?
setter注入通过<property>标签来注入值;
<bean class="com.doubleh.pojo.Student" id="student" > <property name="id" value="1"></property> <property name="name" value="李白"></property> <property name="teacher" ref="teacher"></property> </bean>
各种类型值注入方式:
<bean class="com.doubleh.pojo.Student" id="student" > <!--基础类型--> <property name="id" value="1"> </property> <!--bean引用类型--> <property name="teacher" ref="teacher"></property> <!--数组类型--> <property name="strs" > <array> <value>李白</value> <value>杜甫</value> <value>白居易</value> </array> </property> <!--List类型--> <property name="list"> <list> <ref bean="teacher"></ref> </list> </property> <!--Map类型--> <property name="map"> <map> <entry value="你好" key="a"></entry> <entry key="b" value="发顺丰"></entry> <!--key-ref="" --> <entry key="c" value="{id = 3,name = 设计费}"> </entry> </map> </property> <!--Set类型--> <property name="set"> <set> <value>枪</value> <value>剑</value> </set> </property> <!--Properties类型--> <property name="props"> <props> <prop key="driver">com.mysql.com</prop> <prop key="url">jdbc:mysql://localhost</prop> </props> </property> <!--NULL类型--> <property name="t2"> <null /> </property> </bean>
4.3 p-namespace允许您使用bean
元素的属性(而不是嵌套 <property/>
元素)来描述协作bean的属性值,或同时使用这两者。
<beans></beans>标签中添加配置
xmlns:p="http://www.springframework.org/schema/p"
<!--普通模式--> <!-- <bean id="people" class="com.doubleh.pojo.People"> <property name="name" value="李白"></property> </bean>--> <!--P-namespace注入模式--> <bean id="people" class="com.doubleh.pojo.People" p:name="杜甫"> </bean>
4.4 与具有p-namespace的XML Shortcut相似,在Spring 3.1中引入的c-namespace允许使用内联属性来配置构造函数参数,而不是嵌套constructor-arg
元素。
<beans></beans>标签中添加配置
xmlns:c="http://www.springframework.org/schema/c"