Spring_08_依赖注入

依赖注入

每个基于应用程序的Java都有几个对象,这些对象一起工作来呈现出终端用户所看到的工作的应用程序.当编写一个复杂的java应用程序时,应用程序应该尽可能独立于其他java类来增加这些类的重用的可能性,并且在做单元测试时,测试独立于其他类的独立性.依赖注入(或有时称为布线)有助于把这些类粘合在一起同时保持他们的独立.

加入你又一个包含文本编辑器组件的应用程序,并且你想要提供拼写检查.标准代码看起来是这样的:

public class TestEditor{
    private SpellChecker spellChecker;
    public TextEditor(){
        spellChecker = new SpellChecker();
    }
}

在这里我们所做的就是创建一个TextEditor和SpellChecker之间的依赖关系.在控制反转的常见中,我们而会做这样的事情:

public class TextEditor{
    private SpellChecker spellChecker;
    public TextEditor(){
        spellChecker = new SpellChecker();
    }
}

在这里,TextEditor不应该担心SpellChecker的实现,SpellChecker将会独立实现,并且在TextEditor实例化的时候将提供给TextEditor,整个过程由Spring框架控制.

在这里我们已经从TextEditor中删除了全名控制,并且把它保存到其他地方(即XML配置文件中)并且依赖管子(即 SpellChecker类),通过类构造器被注入到TextEditor类中,因此控制流通过依赖注入(DI)已经"反转",因为你已经有效的委托依赖关系到一些外部系统.

依赖注入的第二种方法就是通过TextEditor类的Setter方法,我们将创建SpellChecker实例,该实例将被用于调用Setter方法来初始化TextEditor的属性.

序号 类型 描述
1 Constructor-based dependency injection 当容器调用带有多个参数的构造函数类时,实现基于构造函数的DI,每个代表在其他类中的一个依赖关系.
2 Setter-based dependecy injection 基于setter方法的DI是通过在调用无参数的构造函数或无参数的静态工厂方法实例化bean之后容器调用beans的setter方法来实现的.

你可以混合这两种方法,基于构造函数和基于setter方法的DI,然而使用有强制性一寸关系的构造函数和有可选依赖的关系的setter是一个好的做法.

代码是DI原理的清洗机,当对象与它们的依赖关系被提供时,解耦效果更明显.对象不查找它的依赖关系,也不知道依赖关系的位置或类,而这一切由Spring框架控制的.

Spring 基于构造函数的依赖注入

当容器调用带有一组参数的类构造函数时,基于构造函数的DI就完成了,其中每个参数代表一个对其他类的依赖.

示例:

步骤 描述
1 创建一个名为 SpringExample 的项目,并在创建的项目中的 c src 文件夹下创建包 com.tutorialspoint.
2 使用 Add External JARs 选项添加必需的 Spring 库,解释见 Spring Hello World Example chapter.
3 在 com.tutorialspoint 包下创建 Java类 TextEditor , SpellChecker 和 MainApp.
4 在 c src 文件夹下创建 Beans 的配置文件 Beans.xml 。
5 最后一步是创建所有 Java 文件和 Bean 配置文件的内容并按照如下所示的方法运行应用程序。

TextEditor.java

package com.tutorialspoint;

public class TextEditor {
    private SpellChecker spellChecker;

    public TextEditor(SpellChecker spellChecker) {
        System.out.println("TextEditor 类中的            带参         构造方法");
        this.spellChecker = spellChecker;
    }

    public void spellCheck() {
        spellChecker.checkSpelling();
    }

}

SpellChecker.java

package com.tutorialspoint;

public class SpellChecker {

    public SpellChecker() {
        System.out.println("SpellChecker类中的      空参方法");
    }

    public void checkSpelling() {
        System.out.println("SpellChecker类中的    checkSpelling() 方法");
    }

}

MainApp.java

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext(
                "Beans.xml");
        TextEditor te = (TextEditor) context.getBean("textEditor");
        te.spellCheck();
    }
}

Beans.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <!-- Definition for textEditor bean -->
    <bean id="textEditor" class="com.tutorialspoint.TextEditor">
        <constructor-arg ref="spellChecker"></constructor-arg>
    </bean>

    <!-- Definition for spellChecker bean -->
    <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
    </bean>

</beans>

当你完成创建源和bean配置后,运行程序可以的到如下展示消息.

SpellChecker类中的      空参方法
TextEditor 类中的            带参         构造方法
SpellChecker类中的    checkSpelling() 方法

构造函数分析:

如果存在不止一个参数时,当把参数传递给构造函数时,可能会存在歧义.要解决这个问题,那么构造函数的参数bean定义中的顺序就是把这些参数提供给适当的构造函数的顺序就可以了.

个人总结:

当初始化TextEditor类时,因为TextEditor类构造函数中需要传递一个类(SpellChecker),故在bean中需要引入ref属性(引用的是bean的id),将bean引入.初始化.

Spring 基于设值函数的依赖注入

当容器调用一个无参构造函数或一个无参静态factory方法来初始化的bean后,通过容器在你的bean上调用设值函数,基于设值函数DI就完成了.

示例:

步骤 描述
1 创建一个名为 SpringExample 的项目,并在创建的项目中的 c src 文件夹下创建包 com.tutorialspoint.
2 使用 Add External JARs 选项添加必需的 Spring 库,解释见 Spring Hello World Example chapter.
3 在 com.tutorialspoint 包下创建 Java类 TextEditor , SpellChecker 和 MainApp。
4 在src 文件夹下创建 Beans 的配置文件 Beans.xml 。
5 最后一步是创建所有 Java 文件和 Bean 配置文件的内容并按照如下所示的方法运行应用程序。

TextEditor.java

package com.tutorialspoint;

public class TextEditor {
    private SpellChecker spellChecker;

    public void setSpellChecker(SpellChecker spellChecker) {
        System.out.println("TextEditor 类中的   setSpellChecker()  方法");
        this.spellChecker = spellChecker;
    }

    public SpellChecker getSpellChecker() {
        return spellChecker;
    }

    public void spellCheck(){
        spellChecker.checkSpelling();
    }

}

这里,你需要检查设置函数方法的名称转换,需要设置一个变量SpellChecker,我们使用setSpellChecker() 方法 该方法与javaPOJO类非常相似,让我们创建另一个依赖文件SpellChecker.java的内容

SpellChecker.java

package com.tutorialspoint;

public class SpellChecker {

    public SpellChecker() {
        System.out.println("SpellChecker类的空参构造");
    }

    public void checkSpelling() {
        System.out.println("SpellChecker类的   checkSpelling()方法");
    }

}

MainApp.java

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext(
                "Beans.xml");
        TextEditor te = (TextEditor) context.getBean("textEditor");
        te.spellCheck();
    }
}

Beans.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <!-- Definition for textEditor bean -->
    <bean id="textEditor" class="com.tutorialspoint.TextEditor">
        <property name="spellChecker" ref="spellChecker"/>
    </bean>

    <!-- Definition for spellChecker bean -->
    <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
    </bean>

</beans>

运行后的结果

SpellChecker类的空参构造
TextEditor 类中的   setSpellChecker()  方法
SpellChecker类的   checkSpelling()方法
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容