依赖注入
1、 什么是依赖?
依赖指的是类之间的访问关系。如果类A访问类B的属性或方法或者类A负责实例化类B,那么可以说类A依赖类B,和关联关系不同,无需把类B定义为类A的属性。在Spring中是通过注入来实现依赖关系的。
2、 什么是依赖注入?
依赖注入背后的基本原理是对象之间的依赖关系(即一起工作的其它对象)只会通过以下几种方式来实现:构造器的参数、工厂方法的参数,或给由构造函数或者工厂方法创建的对象设置属性。
依赖注入作用:容器的工作就是创建bean时注入那些依赖关系。相对于由bean自己来控制其实例化、直接在构造器中指定依赖关系这些自主控制依赖关系注入的方法来说,控制从根本上发生了倒转,这也正是控制反转(Inversion of Control, IoC) 名字的由来。 应用此原则后,代码将更加清晰。而且当bean自己不再担心对象之间的依赖关系(甚至不知道依赖的定义指定地方和依赖的实际类)之后,实现更高层次的松耦合。
依赖注入的主要注入方式有:setter注入和构造器注入。
此外还有接口注入,在此重点介绍setter注入和构造器注入。
3、 setter注入介绍
setter注入通过调用无参构造器或无参static工厂方法实例化bean之后,调用该bean的setter方法,即可实现基于setter的注入。
下面通过一个例子进行介绍:
创建一个DAO接口,接口中有insert和delete两个方法,
创建继承此接口的类GoodsDAO,
创建一个业务实现类GoodsDAOImpl实现了GoodsDAO接口,
创建一个Goods类,包含name和price属性,并实现相应的get和set方法
创建GoodsAction类进行真正的业务处理,包含一个GoodsDAOImpl类型的属性及其get,set方法,还有inert和delete方法代码如下:
public class GoodsAction {
/**此GoodsActionImpl的属性名称gdi一定要与 spring配置文件中propertyname的属性名称一致 必须有相应的set方法与get方法 通过此方法(set方法)注入*/
private GoodsDAOImpl gdi;
/***实现相应的get,set方法/
……………
public String insert() {
System.out.println("-------------------------------");
return "success";
}
public String delete() {
return "success";
}
}
在applicationContext.xml配置文件中进行配置代码如下:
<!-- 定义一个真正业务实现的Bean的实例,通过scope属性指明业务实例对象的作用域 每次请求都会创建一个新实例 -->
<bean id="GDI" class="spr.impl.GoodsDAOImpl" scope="prototype"/>
<!-- 处理业务的Action类 ,创建该bean的一个实例,指明实例的作用域 -->
<bean id="GAction" class="spr.ac.GoodsAction" scope="prototype">
<!-- 通过业务实现类属性gdi的setget方法, ref引用的实例注入到gid属性中 -->
<property name="gdi" ref="GDI"/>
</bean>
创建Test测试类,在main方法里测试代码如下:
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext ("applicationContext1.xml");
GoodsAction ga = (GoodsAction)ac.getBean("GAction");
ga.insert();
}
4、 构造器注入介绍
构造器的注入通过调用带参数的构造器来实现,每个参数代表着一个依赖。
构造器注入方式:构造器参数类型匹配和构造参数索引。
下面通过一个例子进行介绍:
首先在上面的Goods类中添加默认构造器和带有参数的构造器代码如下:
public class Goods {
private String name;
private double price;
public Goods(){
}
public Goods(String name,double price){
this.name=name;
this.price=price;
}
/***实现相应的get,set方法/
……………
}
然后在配置文件中进行配置代码如下:
<bean id="goods" class="spr.impl.Goods" scope="prototype">
<!-- 参数类型匹配, constructor-arg传递构造器的参数,若类中有多个相同类型的属性那么就可以采用构造参数索引方式注入
<constructor-arg type="java.lang.String" value="hp电脑"/>
<constructor-arg type="double" value="100"/>
-->
<!-- 构造参数索引 -->
<constructor-arg index="0" value="hp电脑"/>
<constructor-arg index="1" value="100"/>
</bean>
最后在测试类Test里测试代码如下:
public class Test{
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"ap.xml"}); /**如果要解析多个文件可以定义一个String数组,用逗号隔开*/
Goods gds = (Goods) ac.getBean("goods");
System.out.println("商品的名称"+gds.getName()+" 商品的价格"+gds.getPrice());
}
}