IOC是spring的最基础部分,也是核心模块,Spring的其他组件模块和应用开发都是以它为基础的。IOC把spring的面向接口编程和松耦合的思想体现的淋漓尽致。
IOC概念
IOC(Inversion of Control)译为中文“控制反转”,许多应用都是由两个或更多个类通过彼此合作来实现业务逻辑的,这使得每个对象都要引用其合作对象(也就是它所以来的对象)来装配在一起工作,而这个装配过程如果靠硬编码来实现,他们之间的耦合性有多强就可想而知的。如果把这个装配过程交给第三方(如IOC容器)来实现,那么就能很好的解耦,此时控制就反转了,反转给了第三方(如IOC容器)。
IoC是一个很大的概念,可以用不同的方式来实现。其主要实现方式有两种:
- 依赖查找(Dependency Lookup):容器提供回调接口和上下文环境给组件。EJB和Apache Avalon都使用这种方式。
- 依赖注入(Dependency Injection):组件不做定位查询,只提供普通的Java方法让容器去决定依赖关系。
Dependency Injection是时下最流行的IoC类型,所以有时我们说IOC的另一个名字叫依赖注入,它又有接口注入(Interface Injection),设值注入(Setter Injection)和构造子注入(Constructor Injection)三种方式。
IOC与旧方式的对比
本文Demo想实现的效果:架设需要之前是使用的MySql数据库,但后来却要转向Oracle数据,我们来看下使用IOC和不使用IOC的对比。当然这个例子并不合适,因为你可能立马想到Hibernate,所以请不要介意,这只是个Demo。
- 没有使用注入方式
package net.oseye; public class App { public static void main( String[] args ) { //调用数据库操作 new MysqlHelper().insert(); } } /** * Mysql数据库操作 */ class MysqlHelper{ /** * 插入数据 */ public void insert(){ System.out.println("Mysql数据库插入操作"); } }
package net.oseye; public class App { public static void main( String[] args ) { //调用数据库操作 new OracleHelper().insert(); } } /** * Mysql数据库操作 */ class MysqlHelper{ /** * 插入数据 */ public void insert(){ System.out.println("Mysql数据库插入操作"); } } /** * Oracle数据库操作 */ class OracleHelper{ /** * 插入数据 */ public void insert(){ System.out.println("Oracle数据库插入操作"); } }
- 使用IOC的构造器注入方式
使用IOC你能感受到面向接口编程的思想,App.java代码如下:package net.oseye; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main( String[] args ) { //IOC容器装载Bean定义资源 BeanFactory beanFactory=new ClassPathXmlApplicationContext("applicationcontext.xml"); //依赖装配 IDbHelperManager idbHelperManager= beanFactory.getBean("dbhelpermanager",IDbHelperManager.class); idbHelperManager.insert(); } } /** * 数据库操作管理接口 */ interface IDbHelperManager{ public void insert(); } /** * 数据库操作管理实现 */ class DbHelperManager implements IDbHelperManager{ //构造器注入准备工作 private IDbHelper dbHelper; public DbHelperManager(IDbHelper dbHelper){ this.dbHelper=dbHelper; } public void insert(){ this.dbHelper.insert(); } } /** * 数据库操作接口 */ interface IDbHelper{ public void insert(); } /** * Mysql数据库操作实现 */ class MysqlHelper implements IDbHelper{ public void insert(){ System.out.println("Mysql数据库插入操作"); } } /** * Oracle数据库操作实现 */ class OracleHelper implements IDbHelper{ public void insert(){ System.out.println("Oracle数据库插入操作"); } }
<?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 id="mysqldbhelper" class="net.oseye.MysqlHelper"></bean> <bean id="oracledbhelper" class="net.oseye.OracleHelper"></bean> <bean id="dbhelpermanager" class="net.oseye.DbHelperManager"> <constructor-arg ref="mysqldbhelper"></constructor-arg> </bean> </beans>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>net.oseye</groupId> <artifactId>IOCDemo</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>IOCDemo</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.0.3.RELEASE</version> </dependency> </dependencies> </project>
当你想切换使用Oracle数据库,只需要修改applicationcontext.xml配置文件,把dbhelpermanager的bean配置为oracledbhelper:<bean id="dbhelpermanager" class="net.oseye.DbHelperManager"> <constructor-arg ref="oracledbhelper"></constructor-arg> </bean>
依赖注入三种方式
- 构造器注入
如上面Demo不在累述,构造器注入参数有值类型和引用类型(以下雷同)<constructor-arg ref="引用类型"></constructor-arg> <constructor-arg value="值类型"></constructor-arg>
- setter方法注入
通过 JavaBean的属性分配依赖性,只需要修改DbHelperManager类和配置文件即可。class DbHelperManager implements IDbHelperManager{ //构造器注入准备工作 private IDbHelper dbHelper; public void setDbHelper(IDbHelper dbHelper){ this.dbHelper=dbHelper; } public void insert(){ this.dbHelper.insert(); } }
<?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 id="mysqldbhelper" class="net.oseye.MysqlHelper"></bean> <bean id="oracledbhelper" class="net.oseye.OracleHelper"></bean> <bean id="dbhelpermanager" class="net.oseye.DbHelperManager"> <property name="dbHelper" ref="oracledbhelper"></property> </bean> </beans>
- 接口注入
这种方式不常用,而且具有侵入性,暂不研究!
三种注入方式都是将对象交与IOC容器管理,避免在程序中出现具体实现。通过代码我们可以看出IOC依赖注入的好处:
- 对象之间的依赖关系,不由对象自身来负责,而是由容器依据配置文件动态建立,这样就很灵活,可配;
- 采用依赖注入,模块之间一定是松散耦合的;
- 代码易维护易测试;