IOC (Inversion Of Controll 控制反转)
什么是IOC?
对象之间的依赖关系由容器来建立。
什么是DI? (Dependency Injection 依赖注入)
容器通过调用set方法或者构造器来建立对象之间的依赖关系。
注: IOC是目标,而DI是手段。
依赖注入的两种方式
1.set注入
三个实现类:
package ioc;
public class A {
private IB param;
public void setParam(IB param) {
System.out.println("setParam");
this.param = param;
}
public A() {
System.out.println("A()");
}
public void execute(){
System.out.println("execute");
param.f1();
}
}
package ioc;
public class B implements IB{
public B() {
System.out.println("B()");
}
public void f1(){
System.out.println("B's f1()");
}
}
package ioc;
public class C implements IB{
public C() {
System.out.println("C()");
}
public void f1(){
System.out.println("C's f1()");
}
}
接口:
package ioc;
public interface IB {
public void f1();
}
配置文件:
<bean id="b1" class="ioc.B"></bean>
<bean id="c1" class="ioc.C"></bean>
<!-- property元素:表示使用set方法来注入依赖关系
name属性:指定属性名称
ref属性:指定属性的值(被注入的bean的ID)
-->
<!-- name="abc" 会将a改为大写,调用setAbc()方法 相当于bean属性 -->
<bean id="a1" class="ioc.A">
<property name="param" ref="c1"></property>
</bean>
测试文件:
@Test
//测试set方式注入
public void test4(){
ApplicationContext ac =
new ClassPathXmlApplicationContext("ioc.xml");
A a1 = ac.getBean("a1",A.class);
a1.execute();
/**
* 将B或C注入A的bean中(调用了A类中的set方法)
* 输出结果:
* B()
* C()
* A()
* setParam
* execute
* C's f1() 此处根据配置文件A注入的元素不同有不同的输出
*/
//分析步骤:由于A、B、C单例,先创建A、B、C对象,使用A中set()方法将需注入对象注入到A中
//调用A中的execute()方法,在注入时候使用接口,这样就只修改配置文件即可
}
2.构造器注入
两个实现类
package ioc2;
public class B {
public B() {
System.out.println("B()");
}
public void f1(){
System.out.println("B's f1()");
}
}
package ioc2;
public class A {
private B b;
public A() {
System.out.println("A()");
}
public A(B b) {
System.out.println("A(B)");
this.b = b;
}
public void execute(){
System.out.println("execute()");
b.f1();
}
}
配置文件:
<bean id="b1" class="ioc2.B"></bean>
<!-- constructor-arg元素:用来配置构造器方式注入
index属性指定参数的下标(从0开始)
ref属性:被注入bean的ID
-->
<bean id="a1" class="ioc2.A">
<constructor-arg index="0" ref="b1"></constructor-arg>
</bean>
测试文件:
@Test
public void test1(){
ApplicationContext ac =
new ClassPathXmlApplicationContext("applicationContext.xml");
A a1 = ac.getBean("a1",A.class);
a1.execute();
/**
* B对象通过B的无参构造方法创建,A通过A的有参构造创建,并将B传入A
* 输出结果:
* B() --创建B对象
* A(B) --创建A对象,并将B注入A
* execute() -- 调用execute方法输出
* B's f1()
* 一般情况使用set注入,构造器注入使用较少
*/
}
自动装配 (了解)
什么是自动装配?
容器依据某些规则,自动建立对象之间的依赖关系。
注:默认情况下,容器禁止自动装配。
package ioc2;
public class Waiter {
public Waiter() {
System.out.println("Waiter()");
}
}
package ioc2;
public class Resturatant {
private Waiter wt;
public Resturatant() {
System.out.println("Resturatant()");
}
public void setWt(Waiter wt) {
System.out.println("setWt()");
this.wt = wt;
}
@Override
public String toString() {
return "Resturatant [wt=" + wt + "]";
}
}
配置文件:
<!-- 自动装配 -->
<bean id="wt" class="ioc2.Waiter"></bean>
<!-- autowire属性:自动装配(默认值为no,不自动装配)
该属性有如下三个值:
byName属性:容器根据属性名查找对应的bean的ID(属性名要和bean的ID相同),然后调用set方法完成注入,
如果找不到对应的bean,则注入null,不可能找到多个bean,应为id唯一
byType属性:容器根据属性的类型查找对应的bean,调用对应的set方法来完成注入
如果找不到对应的bean,则注入null,如果找到多个bean,出错
constructor:与byType类似,只不过通过构造器进行注入
-->
<bean id="rest" class="ioc2.Resturatant" autowire="byType"></bean>
测试文件:
@Test
//测试自动装配
public void test3(){
ApplicationContext ac =
new ClassPathXmlApplicationContext("applicationContext.xml");
Resturatant rest = ac.getBean("rest",Resturatant.class);
System.out.println(rest);
/**
* autowire="byName"输出结果:
* Waiter()
* Resturatant()
* setWt()
* Resturatant [wt=ioc2.Waiter@e6a65d]
* 如果找不到对应的bean,则注入null
*/
/**
* autowire="byName"输出结果:
* Waiter()
* Resturatant()
* setWt()
* Resturatant [wt=ioc2.Waiter@1553d26]
* 如果找不到对应的bean,则注入null,找到多个则报错
*/
/**
* constructor:与byType类似,只不过通过构造器进行注入
*/
//自动装配时使用byName最好,最多注入null,且不会报错
}