IOC概念
IOC全称Inversion Of Control,即控制反转,它不是一项技术,而是面向对象编程中的一种设计原则(思想),可以用来降低我们计算机程序代码之间的耦合度,提高优化软件程序设计。它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。也就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。
更通俗的讲,传统的应用程序都是由程序猿同胞们在类内部主动创建对象并实例化,相当于我们的肚子饿了,要自己点外卖来填饱肚子(注入依赖对象)。有了IOC容器,相当于我们找了个女朋友,当我们肚子饿了,由女朋友给我们做饭填饱我们的肚子。女朋友是IOC容器,食物就是依赖对象。我们可以把创建和查找依赖对象的控制权交给容器,由容器注入依赖对象(即实例化对象),这样不仅大大地减少了程序猿的重复工作量,更降低了程序类与类之间的耦合度,提高了程序代码的复用性,使得设计的程序结构体系更加灵活,扩展性更强。
理解IOC,我们要从思想上发生根本性的转变,即主从变化。由原有的程序主动创建并获取依赖对象,到转变为由容器来给到我们一个对象。作为一个程序猿,不应该关心一个对象的产生,而应该交由容器去创建。这样当对象的创建方式改变,对我们程序也不会有影响。以上就是我个人理解的IOC的精髓。
IOC的实现方式
IOC有多种实现方式,其中最常见的叫做“依赖注入”(Dependency Injection,简称DI),另外还有“依赖查找”(Dependency Lookup)和“依赖拖拽”(Dependency Pull)。
什么是依赖?看下面代码就能够理解:IndexServiceImpl类中有个对象属性IndexDao,也就是说IndexServiceImpl依赖IndexDao。
package com.tyyd.service.impl;
import com.tyyd.dao.IndexDao;
import com.tyyd.service.IndexService;
/**
* 测试Sercice实现类
*/
public class IndexServiceImpl implements IndexService {
private IndexDao indexDao;
}
依赖注入(Dependency Injection)
组件不做定位查询,只提供常规的Java方法让容器去决定依赖关系,Spring中依赖注入由三种方式:接口注入(Interface Injection),设值注入(Setter Injection)和构造方法注入(Constructor Injection)三种方式,其中接口注入由于在灵活性和易用性比较差,现在从Spring4开始已被废弃。
接口注入代码:
package com.tyyd.dao;
/**
* DAO接口
*/
public interface IndexDao {
void createIndexDao(IndexDao indexDao);
}
package com.tyyd.service.impl;
import com.tyyd.dao.IndexDao;
import com.tyyd.service.IndexService;
/**
* 测试Sercice实现类
*/
public class IndexServiceImpl implements IndexService, IndexDao {
private IndexDao indexDao;
/**
* 测试方法
*/
public void test() {
indexDao.test();
}
public void createIndexDao(IndexDao indexDao) {
this.indexDao = indexDao
}
}
设置注入代码:
package com.tyyd.service.impl;
import com.tyyd.dao.IndexDao;
import com.tyyd.service.IndexService;
/**
* 测试Sercice实现类
*/
public class IndexServiceImpl implements IndexService {
private IndexDao indexDao;
/**
* 测试方法
*/
public void test() {
indexDao.test();
}
/**
* IOC Set方法注入
* @param indexDao
*/
public void setIndexDao(IndexDao indexDao) {
this.indexDao = indexDao;
}
}
构造方法注入代码:
package com.tyyd.service.impl;
import com.tyyd.dao.IndexDao;
import com.tyyd.service.IndexService;
/**
* 测试Sercice实现类
*/
public class IndexServiceImpl implements IndexService {
@Autowired
private IndexDao indexDao;
/**
* IOC 构造方法注入
* @param indexDao
*/
public IndexServiceImpl(IndexDao indexDao) {
this.indexDao = indexDao;
}
/**
* 测试方法
*/
public void test() {
indexDao.test();
}
}
依赖查找(Dependency Lookup)
public class PigServiceImpl {
private DataSource dataSource;
private PigDao pigDao;
public PigServiceImpl(){
Context context = null;
try{
context = new InitialContext();
dataSource = (DataSource)context.lookup(“java:comp/env/dataSourceName”);
pigDao = (PigDao) context.lookup(“java:comp/env/PigDaoName”);
} catch (Exception e) {
}
}
}
依赖拖拽(Dependency Pull)
即注入的对象如何与组件发生联系,这个过程就是通过依赖拖拽实现。
代码示例:
package com.tyyd.ioc.test;
import com.tyyd.ioc.annotation.service.impl.PigServiceImpl;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("classpath:spring-ioc.xml");
PigServiceImpl pigService = (PigServiceImpl)classPathXmlApplicationContext.getBean("pigServiceImpl");
pigService.test();
}
}
通常我们对注入对象的配置可以通过一个xml文件完成。并使用这种方式对对象进行集中管理,使用依赖拖拽与依赖查找本质的区别是,依赖查找是在业务组件代码中进行的,而不是从一个集中的注册处,特定的地点执行。