一:这里先说一下DI(Dependency Injection)依赖注入有种表现形式:一种是CI(Constructor Injection)构造方法注入,另一种是SI(Set Injection) set 注入。这篇随笔讲的是第一种构造方法注入(Constructor Injection).
其实DI(Dependency Injection)依赖注入你不妨反过来读:注入依赖也就是把"依赖"注入到一个对象中去。那么何为"依赖"呢?依赖就是讲一个对象初始化或者将实例化的时候需要另一个对象,我们把另一个对象成为"依赖"。如构造方法注入(Constructor Injection)就是把依赖当做构造方法的参数注入进去的。如:
//Injection B to A. 我们把B称为依赖。一般情况下B是一个接口,这符合面向接口编程的规范。
public A (B b){
}
二:使用依赖注入的好处是什么?
1.DI(Dependency Injection)最大的好处是decoupling(解耦)。如上面的代码把B注入给A如果B是一个接口或者抽象类。只要任何一个类实现或者继承B都可以注入给A.因此可以达到解耦的目的。
2. 依赖注入给谁?
dependencies injected into the objects that need them.(依赖注入给那些需要他们的对象。)
3.在spring中怎么让依赖传入到被依赖的对象(看上面的代码:怎么把B传入到A中)?
在这里我引用一下spring in action中的一段文字:(注:我下面的示例代码基本跟spring in action 的一样)
The big question here is,how can you give SlayDragonQuest to BraveKnight ? And how can you give a PrintStream to SlayDragonQuest?
The act of creating associations between application components is commonly referred to as wiring.
spring通过配置配置文件,配置bean的形式,完成装配,又装配实现把依赖注入给需要他们的对象中的。
【我这里还想说明一下配置文件中的一个bean其实就对应一个javabean,也就是一个pojo对象,bean就是javabean的缩写形式而已】
示例代码的目录结构如下图所示:
上面中的带两个圈的配置文件想说明两个问题:
一个是:new ClassPathXmlApplicationContext("spring-julysecond.xml");//注意这个.xml文件是在src目录下。
new ClassPathXmlApplicationContext("com/config/spring-julythird.xml")//注意这个.xml文件在com.cofig这个文件下。
另一个问题是DI的解耦问题:spring-julysecond.xml文件中注入的是SlayDragonQuest,spring-julythird.xml注入的是SearchHillQuest.在不改变代码的情况下看传入的Quest的实现类不同,从而打出的结果不同。
spring-julysecond.xml的代码如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd"> 6 <!--this is constructor injection--> 7 <!--the act of creating associations between application components is commonly referred to 8 as wiring--> 9 <bean id="knight" class="com.qls.impl.BraveKnight"> 10 <!-- collaborators and configuration for this bean go here --> 11 <constructor-arg ref="query"></constructor-arg> 12 </bean> 13 <bean id="query" class="com.qls.impl.SlayDragonQuest"> 14 <!-- collaborators and configuration for this bean go here --> 15 <constructor-arg value="#{T(System).out}"/> 16 </bean> 17 <!-- more bean definitions go here --> 18 </beans>
//spring-julythird.xml的代码如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd"> 6 <!--this is constructor injection--> 7 <!--the act of creating associations between application components is commonly referred to 8 as wiring--> 9 <bean id="knight" class="com.qls.impl.BraveKnight"> 10 <!-- collaborators and configuration for this bean go here --> 11 <constructor-arg ref="query"></constructor-arg> 12 </bean> 13 <bean id="query" class="com.qls.impl.SearchHillQuest"> 14 <constructor-arg value="#{T(System).out}"/> 15 </bean> 16 <!-- more bean definitions go here --> 17 </beans>
//Query接口的代码如下:
1 package com.qls.inter; 2 3 /** 4 * Created by ${秦林森} on 2017/6/2. 5 */ 6 public interface Query { 7 void query(); 8 void embark(); 9 } 10 11
//Knight的代码如下:
1 package com.qls.inter; 2 3 /** 4 * Created by ${秦林森} on 2017/6/2. 5 */ 6 public interface Knight { 7 void embarkOnQuest(); 8 }
//Query接口的实现类的代码如下:
//首先是:SlayDragonQuest的代码如下:
1 package com.qls.impl; 2 3 import com.qls.inter.Query; 4 5 import java.io.PrintStream; 6 7 /** 8 * Created by ${秦林森} on 2017/6/2. 9 */ 10 public class SlayDragonQuest implements Query{ 11 private PrintStream stream; 12 13 public SlayDragonQuest(PrintStream stream) { 14 this.stream = stream; 15 } 16 @Override 17 public void embark(){ 18 stream.println("Embarking on quest to slay the dragon"); 19 stream.println("ouyangfeng is the most beautiful woman in the world."); 20 } 21 @Override 22 public void query(){ 23 System.out.println("slay dragon quest"); 24 } 25 }
//其次是SearchHillQuest的代码如下:
1 package com.qls.impl; 2 3 import com.qls.inter.Query; 4 5 import java.io.PrintStream; 6 7 /** 8 * Created by ${秦林森} on 2017/6/3. 9 */ 10 public class SearchHillQuest implements Query{ 11 private PrintStream stream; 12 13 public SearchHillQuest(PrintStream stream) { 14 this.stream = stream; 15 } 16 17 @Override 18 public void query() { 19 20 } 21 22 @Override 23 public void embark() { 24 stream.println("the hero search the hill where the damsel was missing"); 25 } 26 }
//BraveKnight的代码如下:
1 package com.qls.impl; 2 3 import com.qls.inter.Knight; 4 import com.qls.inter.Query; 5 import org.springframework.context.annotation.Configuration; 6 7 /** 8 * Created by ${秦林森} on 2017/6/2. 9 */ 10 11 public class BraveKnight implements Knight{ 12 private Query query; 13 14 public BraveKnight(Query query) { 15 this.query = query; 16 } 17 18 @Override 19 public void embarkOnQuest() { 20 query.embark(); 21 } 22 }
//测试类的代码如下:
1 package com.qls.test; 2 3 import com.qls.inter.Knight; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 6 /** 7 * Created by ${秦林森} on 2017/6/2. 8 */ 9 public class Test { 10 public static void main(String[] args) { 11 /** 12 * 加载配置文件的方式:在src下直接写配置文件的名即可, 13 * 不直接在src下要把前面的包名加上。包名的前面可加也可以不加斜杠/ 14 */ 15 // ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/com/config/spring-julythird.xml"); 16 // ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("com/config/spring-julythird.xml"); 17 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-julysecond.xml"); 18 Knight knight = context.getBean(Knight.class); 19 knight.embarkOnQuest(); 20 context.close(); 21 22 } 23 }