Spring学习笔记:IOC

Spring是一个开源框架,是一个IOC和AOP容器框架

  • IOC:Inversion of Control 控制反转
  • DI:Dependency Injection 依赖注入

主要参考资料:Inversion of Control Containers and the Dependency Injection pattern by Martin Fowler

导论

Martin Fowler举了这样一个例子:类A中有个方法a,需要使用接口B中的方法b,如果用传统模式,我们会在类A内实现接口B的一个实例C,然后再使用方法b,此时类A不仅依赖于接口B,还依赖于接口B的具体实现类C

这样就会带来一个问题:在不同的应用场景中,具体实现方法b是会变化的,那么类A就也要跟着变化,而我们当然希望类A只依赖于接口B,这样就不用在类A内修改方法b,那么要如何获得接口B的具体实现类C呢

这时候就要引入插件的概念:接口B的实现类C不是在编译期连入程序中的,而是要在运行期在类A中插入具体实现类C,也就是要使用插件机制来处理服务之间的交互过程,从而在不同的部署方案中使用不同的实现

将这些插件组合成一个应用程序,便是轻量级容器(比如Spring)的主要任务,解决手段便是采用控制反转模式

控制反转

控制反转是一种思想,一种模式,它决定了容器进行组件装配的方式,以便帮助开发者将来自不同项目的组件组装成为一个内聚的应用程序,控制反转的目标是将组件的配置与使用分离开

  • 控制:传统模式下,我们直接在对象内部通过new进行创建对象并进行相关控制,是程序主动去创建依赖对象;而IOC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建以及外部资源的获取
  • 反转:传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象,对象只是被动的接受依赖,所以是反转

实现控制反转的两种主要模式及其差异性:

  • service locator(服务定位器):应用程序代码直接向服务定位器发送一个消息,明确要求服务的实现
  • dependency injection(依赖注入):应用程序代码不发出显式的请求,服务的实现自然会出现在应用程序代码中

依赖注入模式的基本思想:用一个单独的对象(装配器)来获得接口B的一个合适的实现,并将其实例赋给类A,它最大的好处在于:消除了类A对具体实现类C的依赖

依赖注入的几种形式:

  • 使用PicoContainer进行构造函数注入
  • 使用Spring进行设值方法注入
  • 接口注入

应用Spring实现的一个简单案例

用传统方法写一个hello world程序,我们是直接在方法main里创建一个类HelloWorld的对象helloWorld,然后调用其方法setName()来赋值,最后调用方法hello()输出信息

1
2
3
4
5
6
7
8
9
10
11
12
//HelloWorld.java
public class HelloWorld {
private String name;

public void setName(String name){
this.name = name;
}

public void hello(){
System.out.println("hello:" + name);
}
}
1
2
3
4
5
6
7
8
//Main.java
public class Main {
public static void main(String[] args) {
HelloWorld helloWorld = new HelloWorld();
helloWorld.setName("YQ");
helloWorld.hello();
}
}

引入Spring之后,在方法main中创建对象以及赋值都可以交给Spring来完成,在Spring Bean的配置文件spring-config.xml中,配置好类名class、对象名id、参数名name、参数值value,然后在main方法中利用IOC容器创建对象、获取赋值,并调用方法

1
2
3
4
5
6
7
8
9
//spring-config.xml
<beans>

<!-- 配置bean -->
<bean id="helloWorld" class="cn.yq.abc.HelloWorld">
<property name="name" value="YQ"></property>
</bean>

</beans>
1
2
3
4
5
6
7
8
9
10
11
12
13
//Main.java
public class Main {
public static void main(String[] args) {

//创建spring的IOC容器对象,对IOC容器实例化
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml");

//从IOC容器中获取bean实例,利用id定位到IOC容器中的bean
HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");

helloWorld.hello();
}
}