在讲解Spring依赖注入之前的准备工作:

  • 下载包含Spring的工具jar包的压缩包
  • 解压缩下载下来的Spring压缩包文件
  • 解压缩之后我们会看到libs文件夹下有许多jar包,而我们只需要其中的commons-logging-1.0.4.jar,spring-beans-4.2.1.RELEASE.jar,spring-context-4.2.1.RELEASE.jar,spring-context-support-4.2.1.RELEASE.jar,spring-core-4.2.1.RELEASE.jar,spring-expression-4.2.1.RELEASE.jar
  • 在Eclipse建立一个Dynamic Web Project
  • 将上述必要的几个jar包导入WEB-INF文件夹下lib文件夹中
  • 在src下建立下面提到的包和类

准备工作做完之后我们就开始依赖注入之旅了:

  • 很多人都有迷惑,到底什么是依赖注入,什么是控制反转,其实所说的依赖注入(DI)和控制反转(IOC)是同一概念,他们是不分家的。
  • 通俗来讲就是,当某个角色(调用者)需要另一个角色(被调用者)的协助时,在Java中,通常需要调用者去创建被调用者的实例,即new一个被调用者的对象,而在Spring中,创建被调用者的工作不由调用者完成,因此称控制反转;而创建被调用者的实例由Spring容器来完成,然后注入到调用者,因此也称依赖注入
  • Spring采用配置文件或Annotation(注解)来管理Bean的实现类、依赖关系,Spring容器则根据配置文件,利用反射来创建实例,并为之注入依赖关系。
  • 打个比方吧,在古代生产力及低的社会,人们自给自足,去打猎要自己生产工具Arrow(箭)来捕获自己的猎物,完全是自己动手制造(new)一个箭(对象)。到后来随着社会的发展,有了制造箭工具的工厂,人们无需自己制造箭,而是去工厂告诉他们你需要什么,然后工厂就会给你相应的工具。再后来,你无须到工厂,坐在家里就可以要什么发出个指令,箭就会出现,这里人和箭都是有Spring来管理的,二者依赖关系由Spring提供。

 好了,废话不多说了,下面即将进入我们的正题,依赖注入的三种方式(setter注入、构造注入、接口注入):

  先建立三种方式都会用到的类和接口

    接口:Arrow(箭)、Person(人)

    实现类:ArrowImpl、PersonImpl

    测试类:MainTest

  • setter注入

    Arrow接口:   

package iocdi;

public interface Arrow {
public String getArrow();
}

    Person接口:

package iocdi;

public interface Person {
public void hunt();
}

    ArrowImpl类:

package iocdi;

public class ArrowImpl implements Arrow {

	@Override
public String getArrow() {
return "an arrow";
} }

    PersonImpl类:

package iocdi;

public class PersonImpl implements Person {

	private Arrow arrow;

	@Override
public void hunt() {
System.out.println("I get " + arrow.getArrow() + " to hunt.");
} //set注入一支箭
public void setArrow(Arrow arrow) {
this.arrow = arrow;
} }

    MainTest类:

package iocdi;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; /**
* @author ForeverLover
*/
public class MainTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
System.out.println("-----------------setter注入-----------------");
Person p = ac.getBean("PersonImpl",PersonImpl.class);
p.hunt();
}
}

    看到测试类会有疑问,ApplicationContext.xml从哪儿冒出来的,这里要说的就是Spring容器帮助我们去创建实例对象bean,在进程启动时,Spring容器会自动加载此配置文件,解析通过配置文件配置的bean并创建对应类的实例,被调用者使用指定方式注入到调用者中,从而控制反转和依赖注入。ApplicationContext.xml配置文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <bean id="ArrowImpl" class="iocdi.ArrowImpl"/> <bean id="PersonImpl" class="iocdi.PersonImpl">
<!-- setter注入 -->
<property name="arrow" ref="ArrowImpl"/>
</bean> </beans>

    所有工作都完成了,然后从测试类MainTest的main方法执行一下,从控制台可以看到结果,是OK的:

    

  • 构造注入

  setter注入讲完了,现在我们来聊聊构造注入了,所谓构造注入就是在实例化对象的时候就把参数传给这个对象,我们知道对于JavaBean都必须有构造器,最少有一个无参构造器,到这我们可以继续下面的构造注入,与setter注入不同之处在于,PersonImpl获得ArrowImpl实例的方法,接口Arrow和Person不变,ArrowImpl类也不变,我们修改一下PersonImpl类和ApplicationContext.xml文件:

    修改后的PersonImpl类:

package iocdi;

public class PersonImpl implements Person {

	private Arrow arrow;

	public PersonImpl() {}

	public PersonImpl(Arrow arrow) {
this.arrow = arrow;
} @Override
public void hunt() {
System.out.println("I get " + arrow.getArrow() + " to hunt.");
} }

    修改后的ApplicationContext.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <bean id="ArrowImpl" class="iocdi.ArrowImpl"/> <bean id="PersonImpl" class="iocdi.PersonImpl">
<!-- 构造注入 -->
<constructor-arg ref="ArrowImpl"/>
</bean> </beans>

    然后再次运行一下MainTest测试类,看结果,仍然可行:

    

  • 接口注入

  不同于setter注入和构造注入,接口注入无需在xml文件里配置bean,而利用Java反射创建实现接口类的实例。

    让我们来修改一下MainTest测试类和PersonImpl类:

    修改的PersonImpl类:

package iocdi;

public class PersonImpl implements Person {

	private Arrow arrow;

	@Override
public void hunt() {
try {
Object obj = Class.forName("iocdi.ArrowImpl").newInstance();
arrow = (Arrow) obj;
System.out.println("I get " + arrow.getArrow() + " to hunt.");
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} }

    修改的MainTest类:

package iocdi;

/**
* @author ForeverLover
*/
public class MainTest {
public static void main(String[] args) {
try {
Object obj = Class.forName("iocdi.PersonImpl").newInstance();
Person p = (Person) obj;
System.out.println("-----------------接口注入-----------------");
p.hunt();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}

    运行一下测试类,从控制台得出结果:

    

  • Lookup注入

  说到这顺便说一下Lookup方法注入吧,对于Lookup注入需要一下几个类:

    Arrow类

    Person抽象类

    MainTest测试类

  创建Arrow类:

package iocdi;

import java.util.Random;

public class Arrow {

	private String arrow;
private String[] arrows = {"aaaaArrow", "bbbbArrow", "ccccArrow","ddddArrow","eeeeArrow",
"ffffArrow","ggggArrow","hhhhArrow","iiiiArrow"}; public Arrow() {
this.arrow = arrows[new Random().nextInt(9)];
} public void getArrow() {
System.out.println("I get a " + arrow);
} }

  创建Person类:

package iocdi;

public abstract class Person {

	public abstract Arrow createArrow();

	public Arrow getArrow() {
return new Arrow();
} }

  创建MainTest类:

package iocdi;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; /**
* @author ForeverLover
*/
public class MainTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
Person p = ac.getBean("Person", Person.class);
Arrow arrow1 = p.getArrow();
Arrow arrow2 = p.getArrow();
System.out.println(arrow1.equals(arrow2));
System.out.println("------------I am a dividing line------------");
Arrow arrow3 = p.createArrow();
Arrow arrow4 = p.createArrow();
System.out.println(arrow3.equals(arrow4));
}
}

  修改ApplicationContext.xml配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <bean id="Arrow" class="iocdi.Arrow"/> <bean id="Person" class="iocdi.Person">
<lookup-method name="createArrow" bean="Arrow" />
</bean> </beans>

  最后测试一下,控制台查看一下:

  

  先说一下,分隔线前面之所以会输出false是因为创建的两个对象的引用不同,虽然这里打印出来是eeeeArrow和ddddArrow结果确实不同,因为是随机的,即便有可能结果相同,两个对象的引用也不相同。但是分隔线下面无论如何创建的两个对象的引用相同。大家也可能会疑惑,为什么在配置文件里配置的抽象类也可以实例化对象,并且抽象类中的抽象方法createArrow()并没具体实现却可以创建Arrow实例,这里就跟Spring容器有关,其具体实现了abstarct类,如果createArrow()不是抽象方法,那abstract实现类也会覆盖这个方法。

Spring依赖注入三种方式详解的更多相关文章

  1. spring依赖注入三种方式

    一.构造器注入 构造器注入是在程序中实现构造器,可以注入任意类型,如自定义类,集合,String等,注:构造器所有有final修饰的变量都必须在构造方法中注入. 二.设值注入(setter方式注入) ...

  2. 多表连接的三种方式详解 hash join、merge join、 nested loop

    在多表联合查询的时候,如果我们查看它的执行计划,就会发现里面有多表之间的连接方式.多表之间的连接有三种方式:Nested Loops,Hash Join 和 Sort Merge Join.具体适用哪 ...

  3. Spring依赖注入(DI)详解

    一.依赖简介 一个典型的企业应用程序不是由一个单一的对象组成(或Spring的说法中的bean).即使是最简单的应用程序也只有几个对象一起工作来呈现最终用户看作是一个连贯的应用程序.如何从定义许多独立 ...

  4. React中使用 react-router-dom 路由传参的三种方式详解【含V5.x、V6.x】!!!

    路由传值的三种方式(v5.x) params参数 //路由链接(携带参数): <Link to='/demo/test/tom/18'}>详情</Link> //或 <L ...

  5. Spring——依赖注入(DI)详解

    声明:本博客仅仅是一个初学者的学习记录.心得总结,其中肯定有许多错误,不具有参考价值,欢迎大佬指正,谢谢!想和我交流.一起学习.一起进步的朋友可以加我微信Liu__66666666 这是简单学习一遍之 ...

  6. 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP

    在多表联合查询的时候,如果我们查看它的执行计划,就会发现里面有多表之间的连接方式. 之前打算在sqlplus中用执行计划的,但是格式看起来有点乱,就用Toad 做了3个截图. 从3张图里我们看到了几点 ...

  7. springmvc 异常统一处理的三种方式详解

    1 描述  在J2EE项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的.不可预知的异常需要处理.每个过程都单独处理异常,系统的代码耦 ...

  8. 基于JavaScript 声明全局变量的三种方式详解

    原文地址:http://www.jb51.net/article/36548.htm JS中声明全局变量主要分为显式声明或者隐式声明下面分别介绍. 声明方式一: 使用var(关键字)+变量名(标识符) ...

  9. mysql备份的三种方式详解

    一.备份的目的 做灾难恢复:对损坏的数据进行恢复和还原需求改变:因需求改变而需要把数据还原到改变以前测试:测试新功能是否可用 二.备份需要考虑的问题 可以容忍丢失多长时间的数据:恢复数据要在多长时间内 ...

随机推荐

  1. IOS中图片加载的一些注意点

    图片的加载: [UIImage imageNamed:@"home"] //加载 png图片 在ios中获取一张图片只需要写图片名即可 不需要写后缀 默认都是加载.png的图片 但 ...

  2. 华为手机Edittext光标(cursor)颜色修改

    华为手机的emui系统经常让人发出“可以可以,这很华为”的感叹 这两天在edittext部分也发生了这样的事情 正常edittext光标的颜色和宽度都说可以修改的,只需要通过xml中的 textCur ...

  3. 组合数学 - 母函数的变形 --- hdu 1171:Big Event in HDU

    Big Event in HDU Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  4. 重构第31天 使用多态替代条件语句( Replace conditional with Polymorphism)

    理解:本文中的”使用多态代替条件判断”是指如果你需要检查对象的类型或者根据类型执行一些操作时,一种很好的办法就是将算法封装到类中,并利用多态性进行抽象调用. 详解:本文展示了面向对象编程的基础之一“多 ...

  5. 重构第17天提取父类(Extract SuperClass)

    今天的重构来自 Martin Fowler的http://refactoring.com/catalog/extractSuperclass.html. 理解:本文中的“提取父类”是指类中有一些字段或 ...

  6. csharp: NHibernate and Entity Framework (EF) (object-relational mapper)

    代码生成器: 1. http://www.codesmithtools.com/ 2.https://sourceforge.net/projects/mygeneration/ 3. http:// ...

  7. [转]PDO防注入原理分析以及使用PDO的注意事项

    原文:http://zhangxugg-163-com.iteye.com/blog/1835721 好文章不得不转. 我们都知道,只要合理正确使用PDO,可以基本上防止SQL注入的产生,本文主要回答 ...

  8. 如何安装nodejs

    1.进入官网https://nodejs.org/en/download/ 2.安装过程基本直接“NEXT”就可以了.(windows的安装msi文件在过程中会直接添加path的系统变量,变量值是你的 ...

  9. YII页面跳转

    $criteria = new CDbCriteria; $criteria->select = array('ziduan"); $res = Model::model()-> ...

  10. php学习笔记:利用gd库生成图片,并实现随机验证码

    说明:一些基本的代码我都进行了注释,这里实现的验证码位数.需要用的字符串都可以再设置.有我的注释,大家应该很容易能看得懂. 基本思路: 1.用mt_rand()随机生成数字确定需要获取的字符串,对字符 ...