【Spring源码解析(三)】从IOC说起,究竟什么是控制反转
刚工作的时候完全无法理解ioc是什么,看着书上的控制反转,依赖注入,仿佛怀疑人生,每个字都认识,可是就是无法理解。现在看来当时的学习方法也有点错误,执着于想通过看书理解spring,随着工作的进行,发现,其实这是一个很简单的东西。而且ioc这样翻译过来也很合理,ioc:Inversion of Control。一般中文叫做,控制反转或者依赖注入(DI)。究竟是在控制什么,反转什么,又是什么依赖了谁,谁进行了注入。
其实ioc是一种思想,并不是什么技术,这种思想不仅在spring被应用了,在struts中同样有应用,比如我们在ssh框架中开发是,action层的类有没有被实例化,当然有,否则怎么会执行其中的方法来响应请求,但是好像从来没有去对action层中的类进行创建对象的操作。其实不是,struts2中每一次请求,都会帮你创建一个对象,在struts.xml配置文件中,<action>标签中就做了这样的工作,具体细节还关系到拦截器等概念,这里不说struts2,只是强调ioc这种思想是应用广泛的。
我们来说spring中的ioc,究竟为什么要这样做呢,本文用几个例子,来看一下ioc的前世今生。没有ioc的时候程序员是如何工作的,有了ioc这种方法后又是怎么实例化对象的。
(一)ioc的由来
新建一个java项目spring_ioc,目录如下:
dao层中有两个类实现了接口IUserDao,service层调用dao层,最后在test中进行测试。如果没有ioc,那么这是怎么做的呢?没错,new一个对象。
IUserDao.java:
public interface IUserDao {
public void getUser();
}
上图中就是这样来创建对象的,但是这时候就有一个问题,此时得userDao是通过new了一个实现类,实现类中并不只有UserDaoMySqlImpl,假如在项目过程中需要更改成UserDaoOracleImpl使用,那么会导致所有的service层中实例化userDao的类中都要改动,这是非常麻烦的。那么如何改动呢?我们可以把实例化的过程交给客户端,而不是程序本身。比如:
上图就解决了上述问题,我们不再需要把对dao层的实例化在service层中进行,只需要提供一个接口就可以了。这样在实例化的事情就交给了客户端。
以上就是ioc的原型,这样做有这样几点好处:
- 对象由本身创建,变味了程序接受对象;
- 程序员主要的精力就可以集中于业务的实现;
- 实现了service和dao的解耦工作,service层和dao层实现了分离,没有直接的依赖关系;
- 如果dao发生改变,应用程序本身不用改变。
那么spring究竟是如何做的呢?第二个例子。
(二)hello spring
准备一下spring需要的jar包,下载地址。并不是全部都要的,具体见下图,足够了,再用再加就是了。
步骤:
- 导入jar包,idea如何导入jar包;
- 编写spring配置文件,名字可以任意起,这点和struts2不太一样哦;
hello.java:
public class Hello {
private String name;
public void setName(String name){
this.name = name;
}
public void show(){
System.out.println("hello,"+name);
}
}
bean.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- bean就是java对象,由spring来创建和管理 -->
<bean name="hello" class="com.gfc.bean.Hello">
<property name="name" value="郭富城"/>
</bean>
</beans>
测试代码test.java:
public class test {
public static void main(String[] args) {
//解析bean.xml
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Hello hello = (Hello) context.getBean("hello");
hello.show();
}
}
从这个例子中我们好像没有直接去new一个Hello对象,但是最终在测试代码中仍然有了Hello里方法的调用,那么究竟有没有创建呢,当然创建了,否则怎么会有实例hello。那么究竟是谁创建了Hello的对象hello呢?答案就是spring啦!准确的来讲,是spring容器去创建了。Hello对象属性是由spring容器设置的。
这个过程就是控制反转:
控制的内容:指谁来控制对象的创建;传统的应用程序对象的创建是程序本身,使用spring之后,是由spring来创建对象的。
反转:与反转相对的就是正常的一个过程,就是我们说的程序来创建对象,可以理解成正转;反转呢就是指程序本身不去创建对象,而变成被动的接受对象。
总而言之,以前对象是由程序本身去创建,使用spring后,程序变成了被动接收spring容器创建好的对象。
开头说了,控制反转又被称为依赖注入(DI:dependency injection)。结合一下上述例子,Hello中依赖于name这个属性,而name的值呢,是由容器给的,这个就是依赖注入了,只不过实际项目中我们更多注入的依赖不是一个简单的name字符串属性,而是某个由spring创建好的对象属性。
说到这里,我想容器究竟是如何注入的呢,结合上面的例子,可以看到在Hello类中有一个setName()的方法,spring就是利用set方法,对属性进行了注入。接下来继续说一下。
(三)IOC的真面
Ioc不是什么技术,它是一种思想,由主动编程变为被动接收,ioc的实现是通过ioc容器来实现的。那么ioc容器是什么呢:BeanFactory !关于BeanFactory会专门讲解。
上一篇: IntelliJ IDEA优秀插件