依赖注入定义:
组件依赖于抽象,当组件要与具体实现类产生依赖,则通过抽象注入实际对象。组件和具体实现类的关系由抽象进行中转。
XXX 注入 XXX
注入具体实现类
通过抽象注入具体实现类。
依赖注入的三种方式: 1、接口注入:一般定义一个接口,逻辑类实现该接口和该接口定义的方法, 在必须实现的方法中通过抽象类注入具体实现类。
2、set注入:通过set方法,set某一个具体实现类,或者在xml配置文件中配置。
3、构造器注入:在接受注入的类中定义一个构造方法,并在参数中定义需要注入的元素。构造器注入的xml配置和set注入有写区别。
详细说明各种注入:
(一)接口注入:
1、具体类的抽象类
2、具体实现类
3、注入类(注入类接口,注入类实现接口的方法)
4、测试类,new一个注入类,调用实现的方法。
实例代码:
具体类的抽象类
package com.gc.impl; //编写接口,实现依赖抽象 public interface DataBase { public abstract void getDataBase(); }
实现具体类
package com.gc.acion; import com.gc.impl.DataBase; public class OracleDataBase implements DataBase{ @Override public void getDataBase() { // TODO Auto-generated method stub //oracle获取数据的方法 } }
package com.gc.acion; import com.gc.impl.DataBase; public class DB2DataBase implements DataBase{ @Override public void getDataBase() { // TODO Auto-generated method stub //db2获取数据的方法 } }
定义注入类接口,所有实现该接口的类都必须实现抽象方法,从而达到注入的目的。
package com.gc.impl; //接口注入,通过实现该接口中所有的方法,给所有实现该接口的类都注入了DataBase的实现类 public interface IDataBaseBusinnes { public abstract void creatDI(DataBase dataBase); }
注入类的实现
package com.gc.acion; import com.gc.impl.DataBase; import com.gc.impl.IDataBaseBusinnes; //业务逻辑层,获取数据时通过接口进行编程,而不是具体类(实现依赖抽象即业务逻辑实现类通过抽象的接口去编写,而不是抽象依赖实现) public class DataBaseBusinnes implements IDataBaseBusinnes{ private DataBase dataBase = null; //根据注入的数据库类获取具体的数据库数据 public DataBase getDataBase(){ return dataBase; } //接口注入 @Override public void creatDI(DataBase dataBase) { // TODO Auto-generated method stub } }
测试类:
new DataBaseBusinnes
package com.gc.test; import com.gc.acion.DataBaseBusinnes; import com.gc.acion.OracleDataBase; public class DataBaseTest { public static void main(String[] args) { DataBaseBusinnes dbbussinnes = new DataBaseBusinnes(); //接口注入 dbbussinnes.creatDI(new OracleDataBase()); dbbussinnes.getDataBase(); } }
(二)set注入:
可以通过配置文件注入也可以不通过配置文件注入:
具体实现类的抽象类:
package com.gc.impl; //编写接口,实现依赖抽象 public interface DataBase { public abstract void getDataBase(); }
具体实现类:
package com.gc.acion; import com.gc.impl.DataBase; public class OracleDataBase implements DataBase{ @Override public void getDataBase() { // TODO Auto-generated method stub //oracle获取数据的方法 } }
package com.gc.acion; import com.gc.impl.DataBase; public class DB2DataBase implements DataBase{ @Override public void getDataBase() { // TODO Auto-generated method stub //db2获取数据的方法 } }
注入类:通过set方法抽象注入DataBase
package com.gc.acion; import com.gc.impl.DataBase; //业务逻辑层,获取数据时通过接口进行编程,而不是具体类(实现依赖抽象即业务逻辑实现类通过抽象的接口去编写,而不是抽象依赖实现) public class DataBaseBusinnes{ private DataBase dataBase = null; //根据注入的数据库类获取具体的数据库数据 public DataBase getDataBase(){ return dataBase; } //set注入 public void setDataBase(DataBase dataBase){ this.dataBase = dataBase; } }
测试类:set注入
dbbussinnes.setDataBase(new OracleDataBase());package com.gc.test; import com.gc.acion.DataBaseBusinnes; import com.gc.acion.OracleDataBase; public class DataBaseTest { public static void main(String[] args) { DataBaseBusinnes dbbussinnes = new DataBaseBusinnes(); dbbussinnes.setDataBase(new OracleDataBase()); dbbussinnes.getDataBase(); } }
有一种情况是
dbbussinnes.setDataBase(new OracleDataBase());
set方法是不要的,在配置文件里给DataBase指向具体的实现得到bean,再通过这个bean类的方法getDataBase();
这种就是通过配置文件注入,更方便
(三)构造函数注入
可以通过配置文件的方法注入和不通过配置文件的方式注入
具体实现类的抽象类
package com.gc.impl; //编写接口,实现依赖抽象 public interface DataBase { public abstract void getDataBase(); }
具体实现类
package com.gc.acion; import com.gc.impl.DataBase; public class OracleDataBase implements DataBase{ @Override public void getDataBase() { // TODO Auto-generated method stub //oracle获取数据的方法 } }
package com.gc.acion; import com.gc.impl.DataBase; public class DB2DataBase implements DataBase{ @Override public void getDataBase() { // TODO Auto-generated method stub //db2获取数据的方法 } }
注入类
package com.gc.acion; import com.gc.impl.DataBase; //业务逻辑层,获取数据时通过接口进行编程,而不是具体类(实现依赖抽象即业务逻辑实现类通过抽象的接口去编写,而不是抽象依赖实现) public class DataBaseBusinnes{ private DataBase dataBase = null; //构造函数 public DataBaseBusinnes(DataBase dataBase){ this.dataBase = dataBase; } //根据注入的数据库类获取具体的数据库数据 public DataBase getDataBase(){ return dataBase; } }
测试类
package com.gc.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; import com.gc.acion.DataBaseBusinnes; import com.gc.acion.OracleDataBase; public class DataBaseTest { public static void main(String[] args) { //不通过配置文件的方式注入 //DataBaseBusinnes dbbussinnes = new DataBaseBusinnes(new OracleDataBase()); //通过配置文件的方式注入 ApplicationContext context = new FileSystemXmlApplicationContext("config.xml"); DataBaseBusinnes dbbussinnes = (DataBaseBusinnes)context.getBean("DataBase"); dbbussinnes.getDataBase(); } }
构造函数的xml配置:
<!-- 构造函数注入 ,constructor-arg表示通过构造函数注入的方式注入,index="0"表示构造函数的第一个参数,如果只有一个参数可省略--> <bean id="DataBase" class="com.gc.acion.OracleDataBase"> <constructor-arg index="0"> <value>OracleDataBase</value> </constructor-arg> </bean>
以上三种方式的不同均在注入类的注入方式不同,有通过接口的,有通过set方法的,有通过构造函数的。
关于选用哪种注入方式的问题,构造注入是在对象创建时期就完成注入,set注入的方式是在创建对象完成后进行注入。一般使用set注入会稍微多一些。