我们常常会遇到这样一种情景。就是在我们开发项目的时候常常会在一个类中调用其它的类中的方法,来完毕我们期望的任务。大部分的情况下往往会採用在当前需要的这个类里面new一个实例出来。然后调用他的方法,那么这种话会有个问题。就是有一天我想改变下这个类,改为其它的名称。那么这时候必需要做的是同一时候去调用方的类文件里改变这个改变的类的名称。这种情况是由于代码的耦合带来了后期维护成本的添加,那么spring的出现就能够非常好的起到解耦的作用,而他的核心机制就是依赖注入。
依赖注入与控制反转
依赖注入:对于spring而言。将自己置身于spring的立场上去看。当调用方须要某一个类的时候我就为你提供这个类的实例,就是说spring负责将被依赖的这个对象赋值给调用方。那么就相当于我为调用方注入了这种一个实例。从这方面来看是依赖注入。
控制反转:对于调用方来说,通常情况下是我主动的去创建的,也就是对于这个对象而言我是控制方,我有他产生与否的权力。可是,如今变了,如今变为spring来创建对象的实例。而我被动的接受,从这一点上看,是控制反转。
这两者的意思是一致的。就看你从谁的角度去看这个问题。
不同的角度那么看到的问题可能是不一样的。
依赖注入两种方式
1.设值注入
设值注入:通过set的方式注入值.Ioc容器通过成员变量的setter方法来注入被依赖的对象,这样的注入方式简单,直观。因而在spring中大量的使用。
以下我们採用实际的样例来体会一下:
如果这种一个场景,我想打印消息。这样一件事情
首先定义一个MessageService的接口。
-
package com.siti.spring20160227;
-
-
public interface MessageService {
-
-
-
-
-
public void printMessage();
-
}
然后实现这个接口,并实现这种方法。
-
package com.siti.spring20160227;
-
-
public class MessagePrinter implements MessageService {
-
-
@Override
-
public void printMessage() {
-
System.out.println("输出消息!");
-
}
-
-
}
那么对于我而言,我也定义一个person的接口
-
package com.siti.spring20160227;
-
-
public interface Person {
-
-
-
-
-
public void sendMessage();
-
}
我来实现人这个接口
-
package com.siti.spring20160227;
-
-
public class WangYang implements Person{
-
-
private MessageService service;
-
-
public void setService(MessageService service) {
-
this.service = service;
-
}
-
-
@Override
-
public void sendMessage() {
-
this.service.printMessage();
-
}
-
-
}
Spring的配置文件:
-
<?
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:
-
-
<!-- bean definitions here -->
-
<bean id = "messageService" class = "com.siti.spring20160227.MessagePrinter"></bean>
-
<bean id = "wy" class = "com.siti.spring20160227.WangYang">
-
<property name="service" ref="messageService"></property>
-
</bean>
-
</beans>
測试类例如以下:
-
package com.siti.spring20160227;
-
-
import org.springframework.context.ApplicationContext;
-
import org.springframework.context.support.ClassPathXmlApplicationContext;
-
-
public class MainTest {
-
-
public static void main(String[] args) {
-
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
-
Person person = context.getBean("wy", Person.class);
-
person.sendMessage();
-
}
-
}
2.构造注入
通过构造函数的方式注入。
spring以反射的方式运行带指定參数的构造器,当运行带參数的构造器时就能够通过构造器的參数赋值给成员变量,完毕构造注入。
那么如今需求变了。我须要改一些东西,以下能够注意下我主要修改了哪里:
在WangYang这个类中加入有參数和无參数的构造函数:
-
package com.siti.spring20160227;
-
-
public class WangYang implements Person{
-
-
private MessageService service;
-
-
<span style="color:#33ff33;">public WangYang() {
-
super();
-
}
-
-
public WangYang(MessageService service) {
-
this.service = service;
-
}
-
-
</span>public void setService(MessageService service) {
-
this.service = service;
-
}
-
-
@Override
-
public void sendMessage() {
-
this.service.printMessage();
-
}
-
-
}
在Spring配置文件里,略微修改。即将原来的设值注入换为构造注入就可以。
-
<?
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:
-
-
<!-- bean definitions here -->
-
<bean id = "messageService" class = "com.siti.spring20160227.MessagePrinter"></bean>
-
<bean id = "wy" class = "com.siti.spring20160227.WangYang">
-
<!-- <property name="service" ref="messageService"></property> -->
-
<span style="color:#33ff33;"><constructor-arg ref="messageService"></constructor-arg></span>
-
</bean>
-
</beans>
这样再次执行MainTest类。程序正常执行。所以从这里也能够体会到,spring这样的解耦的方便性和重要性。
设值注入和构造注入的对照
这两种方式。效果是一样的,注入的时机不同,设值注入是先调用无參的构造函数,创建出实例后然后调用set方法注入属性值。而构造输入是通过在调用构造函数初始化实例的同一时候完毕了注入。
设值注入的长处
1. 通过set的方式设定依赖关系显得更加直观。自然,和javabean写法类似。
2. 复杂的依赖关系,採用构造注入会造成构造器过于臃肿,spring 实例化的时候同一时候实例化其依赖的所有实例。导致性能下降,set方式能够避免这些问题。
3. 在成员变量可选的情况下,构造注入不够灵活。
构造注入的长处
某些特定的情况下。构造注入比设值注入好一些。
1. 构造注入能够在构造器中决定依赖关系的注入顺序,优先依赖的优先注入,构造注入能够清楚的分清注入的顺序。
2. 组件的调用者无需知道组件内部的依赖关系,符合高内聚原则。