IoC(Inverse of Control)控制反转,是Spring的两大特点之一
IoC通过两种方式实现:依赖查找(DL)和依赖注入(DI)
DL已经被抛弃,因为他需要用户自己去使用API进行查找资源和组装对象。即有侵入性,与Spring的无侵入性相违背
DI是Spring目前使用的方式,容器负责组件的装配。Spring支持的构造函数注入和属性注入。
构造注入
通过一个旧的例子来说明构造注入,墨攻中,刘德华饰演墨者革离,守军询问他是谁,他回答"墨者革离"
public class MoAttack{//编写一个剧本成员
private GeLi geli;//设置一个角色革离
public MoAttack(GeLi geli){//在构造函数进行注入,该成员为革离
this.geli = geli;
}
public void cityGateAsk(){//回答守军
geli.responAsk("墨者革离");
}
}
public class Director{
public void direct(){
Geli geli = new LiuDeHua();//实例化一个Geli对象
MoAttack moAttack = new MoAttack(geli);//通过构造函数注入
moAttack.cityGateAsk();//结果返回的是墨者革离,而非刘德华
}
}
从上面的例子我们可以看出来,当守军问"来者何人"的时候,无论他是刘德华,还是张德华,只要是饰演革离的人都是回答"墨者革离",但是很重要的一个问题,主角是不是每次都会出场,如果不是我们应该怎么做?
属性注入
public class MoAttack{//编写一个剧本成员
private GeLi geli;//设置一个角色革离
public void setGeli(GeLi geli){//通过set方法,属性注入,当需要革离的时候才分配革离的演员
this.geli= geli;
}
public void cityGateAsk(){//回答守军
geli.responAsk("墨者革离");
}
}
public class Director{
public void direct(){
Geli geli = new LiuDeHua();//实例化一个Geli对象
MoAttack moAttack = new MoAttack();//通过构造函数创建一个剧本成员
moAttack.setGeli(geli);//通过属性setter注入依赖,安排革离演员
moAttack.cityGateAsk();//结果返回的是墨者革离,而非刘德华
}
}
通过属性注入的方式,我们可以避免每一次构建MoAttack都需要注入一个GeLi对象。这样就可在不同的场景通过setter注入不同的角色
对于IoC来说,最重要的就是容器。容器管理者Bean的生命周期。
Spring设计了两类容器
- BeanFactory,Spring的基础设施,面向Spring。只提供注册(put),获取(get)两个功能。
- ApplicationContext,面向Spring框架的开发者。
图片转载自
上述是较为完整的ApplicationContext类继承体系
ClassPathXmlApplicationContext的大概构造过程为
- 用户构造ClassPathXmlApplicationContext
- ClassPathXmlApplicationContext首先访问高级容器中的refresh方法,这个是个模板方法,需要回调子类(低级容器)的refreshBeanFactory方法,这个方法的作用是使用低级容器加载所有BeanDefinition和Properties到容器中
- 低级容器加载成功后,高级容器开始处理一些回调。(功能越来越多,越来越迷茫)
总结
BeanFacotory的IoC只需要两个步骤:
- 加载配置文件,解析成BeanDefinition放在Map里
- 调用getBean的时候,从BeanDefinition所属的Map里,拿出Class对象进行实例化,同时,如果有依赖关系,将递归调用getBean方法-完成依赖注入
Application包含低级容器的功能,当他执行refreesh模板方法的时候,将刷新整个容器的Bean,同时作为高级容器,包含太多的功能,一句话,它不仅仅是Ioc。他支持不同信息源头,支持 BeanFactory 工具类,支持层级容器,支持访问文件资源,支持事件发布通知,支持接口回调等等。