Spring框架是现在非常流行的框架之一,其两大核心技术IoC(依赖注入/控制反转)和AOP(面向切面编程),使得应用程序的组件更加快捷简易。本文用实例先对IoC的做详细介绍,希望对初学者有一定的帮助,本人能力有限,对于文章中的错误欢迎各位同道中人指正。
IoC使用两大关键技术(JDOM、反射机制)和一个设计模式(工厂模式)来实现将组建对象的控制权从代码本身转移到外部容器,以降低代码之间的耦合度。下面用代码实例的形式来说明IoC原理。
1.dao层(一个接口)
package cn.dao;
public interface DaoInte{
public void daoMethod();
}
2.dao实现层(两个类)
package cn.dao.impl;
import cn.dao.DaoInter;
public class DaoClass1 implements DaoInter{
@Override
public void daoMethod() {
System.out.println("假设这是这个类用来查询数据库的student表");
}
}
package cn.dao.impl;
import cn.dao.DaoInter;
public class DaoClass2 implements DaoInter{
@Override
public void daoMethod() {
System.out.println("假设这是这个类用来查询数据库的student表,此表经过大量的更新,包括表结构和数据");
}
}
3.service层(一个接口)
package cn.service;
public interface ServiceInte {
public void method1();
}
4.service实现层(一个类)
package cn.service.impl;
import cn.dao.DaoInte;
import cn.service.ServiceInte;
public class ServiceClass implements ServiceInte{
private DaoInte dao; //两种方法调用dao层的daoMethod
//---------不使用IoC-----------
public void method1(){
dao=new DaoClass1; //创建dao实现层DaoClass1对象,当需求更改后要创建DaoClass2对象,这是就需要更改这里的代码
dao.daoMethod(); //调用方法
}
//---------使用IoC------------
private DaoInte getDao() {
return dao;
}
public void setDao(DaoInte dao) {
this.dao = dao;
}
public void method1(){
dao.daoMethod();
}
}
5.Spring配置文件(使用IoC时)
<beans>
<bean id="daoBean" class="cn.dao.impl.DaoClass1"></bean>
<!-- class值为类相对于配置文件的路径,当需要更改dao实现类时,只需要更改这里即可,即将class值改为DaoClass2,而不需要更改代码 -->
<bean id="testService" class="cn.service.impl.ServiceClass">
<property name="dao">
<!-- 给service实现层中的dao属性赋值 ,实际上是在调用里面的set方法,此处使用到*反射机制*-->
<ref bean="daoBean"/>
</property>
</bean>
</beans>
可以看到,不使用Spring IoC时,调用service层,必须先new对象,将service层的接口指向具体的ServiceClass对象,才能调用其中的方法,即:
ServiceInte svi=new ServiceClass();
svi.method1();
这又将产生调用类与service层的耦合,当更改service层具体实现类时,就需要更改这里的代码。而在ServiceClass对象中需要调用dao层,此时也需要先new对象,将dao层接口指向具体的DaoClass1对象或者DaoClass2对象,这样也产生了耦合关系,代码见如上第4条不使用IoC。
总结就是,测试类管理service层的类的调用,service层管理dao层的类的调用,当更改dao层或service层的实现类,就需要更改代码来实现,当更改的需求越来越多时,将会使代码混乱。此时就需要解耦合,消除他们的依赖关系,可以建立一个bean工厂,在这个工厂中生成bean实例,并将这个实例推送给具体的调用类,那么我在这个工厂中生成什么样的bean,要调用的类就使用什么样的bean,更改时只需要更改这个工厂要生成的bean的具体实现就可以了,spring利用配置文件来完成这个工厂的创建,这就是工厂模式,代码如上第四条使用IoC和第五条配置文件的创建。到目前只是解决了service层与dao层的耦合关系,并没有解决调用service层时产生的耦合关系,实际上我们在Spring配置文件中第二个bean已经产生了具体的ServiceClass对象,其id为设置的”testService”,所以调用使就不再需要如上new对象,而是可以使用这里的ServiceClass对象,使用方法如下:
//加载配置文件(相对路径)
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//加载配置文件(绝对文件)
//new FileSystemXmlApplicationContext("..");
ServiceClass sc=(ServiceClass)ctx.getBean("testService");
sc.method1();
这样就解决了调用service层时的耦合问题,当service层变更时只需要更改配置文件里的路径指向,而不需要更改代码。下面用一张图简单解释这种关系:
因此IoC被翻译为依赖注入或控制反转。通俗的说,IoC使得原本程序中需要什么样的对象就new什么样的对象变成配置文件的bean工厂给什么样的对象就使用什么样的对象,是一个由主动变被动的过程。