[译]12-spring依赖注入

每个java应用程序都是由多个类协作才最终生成了终端用户所使用的系统.当编写复杂java应用程序的时,类之间应尽

可能保持独立,因为这样更容易做到代码的重用,也有利于单元测试的开展.spring的依赖注入功能能在保持类相互独立

的同时把他们"粘合"起来.

考虑如下场景:你的应用程序中有个文本编辑器组件,你现在想给你的文本编辑器添加拼写检查的功能.那么你可能写

出如下的代码来:

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

在上述大代码中TextEditor类中聚合了SpellChecker类,这里我们称SpellChecker为TextEditor类的依赖项.而且依

赖项实例化的工作是在TextEditor内部完成的。这种看似理所当然的代码,其实是有相当大的问题的.这里直接实例化

SpellChecker类.而在实际应用中,拼写检查工具会有不同的实现,如果我们想切换TextEditor的SpellChecker的实现

类就必须修改代码。

在使用了控制反转框架之后,写出的代码会是如下这样:

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

在这段代码中SpellChecker是通过TextEditor的构造器传入的.TextEditor不必关心SpellChecker的实现.具体的实

现类是由spring容器在实例化的TextEditor的时候注入的.

由于TextEditor对依赖项SpellChecker的控制权从TextEditor转移到了spring容器,即控制权发生了反转.控制权发

生反转的方式是通过依赖注入(原理是Java的反射)来实现的.

spring中依赖注入的方式有两种:

  1. 通过bean的构造器参数进行注入
  2. 通过bean的setter方法进行依赖注入.实例化bean之后,spring容器会反射调用bean的setter方法.

下面我们将分别讲解着两种依赖注入的方式。

构造器参数进行依赖注入

使用构造器参数进行依赖注入,spring容器会在实例化bean的时候把bean的依赖项通过bean的带参的构造函数进行

注入.下面用一个例子进行演示:

1.创建包com.tutorialspoint.di,并在包内新建TextEditor.java和SpellChecker.java,内容分别如下:

TextEditor.java如下:

package com.tutorialspoint.di;

public class TextEditor {
    
    private SpellChecker spellChecker;

    public TextEditor(SpellChecker spellChecker) {
        System.out.println("Inside TextEditor constructor.");
        this.spellChecker = spellChecker;
    }

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

SpellChecker.java如下:

package com.tutorialspoint.di;

public class SpellChecker {
    
    public SpellChecker() {
        System.out.println("Inside SpellChecker constructor.");
    }

    public void checkSpelling() {
        System.out.println("Inside checkSpelling.");
    }

}

2.在src目录下新建di.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">

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

   <bean id="spellChecker" class="com.tutorialspoint.di.SpellChecker"/>

</beans>

3.在包com.tutorialspoint.di中新建MainApp.java,内容如下:

package com.tutorialspoint.di;

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

public class MainApp {
    
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("di.xml");

        TextEditor te = (TextEditor) context.getBean("textEditor");

        te.spellCheck();
        
    }
}

4.运行程序,检查结果:

使用构造器参数进行依赖项的注入,有时候会产生歧义.这时候可以使用type属性进行歧义的消除.

set方法依赖注入

spring也可以使用set方法进行依赖注入.当bean实例化以后,spring容器会反射调用bean实例的set方法进行依赖项

的注入.在基于xml的配置文件中可以使用bean元素的property子元素指定需要使用setter进行注入的依赖项.

下面看个例子

1.创建包com.tutorialspoint.di.setter.并在包中新建TextEditor.java和SpellChecker.java,内容分别如下:

TextEditor.java

package com.tutorialspoint.di.setter;

public class TextEditor {
    
    private SpellChecker spellChecker;

    public void setSpellChecker(SpellChecker spellChecker) {
        System.out.println("Inside setSpellChecker.");
        this.spellChecker = spellChecker;
    }

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

 SpellChecker.java

package com.tutorialspoint.di.setter;

public class SpellChecker {
    
    public SpellChecker() {
        System.out.println("Inside SpellChecker constructor.");
    }

    public void checkSpelling() {
        System.out.println("Inside checkSpelling.");
    }

}

2.在src目录下新建di_setter.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">

   <bean id="textEditor" class="com.tutorialspoint.di.setter.TextEditor">
      <property name="spellChecker" ref="spellChecker"/>
   </bean>

   <bean id="spellChecker" class="com.tutorialspoint.di.setter.SpellChecker"/>

</beans>

 3.在包com.tutorialspoint.di.setter中新建MainApp.java类,内容如下:

package com.tutorialspoint.di.setter;

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

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("di_setter.xml");

        TextEditor te = (TextEditor) context.getBean("textEditor");

        te.spellCheck();
    }
}

4.运行程序,检查结果:

setter方法进行依赖注入的xml配置方式支持p命名空间,使用p命名空间可以减少配置文件大小,把di_setter.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:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="textEditor" class="com.tutorialspoint.di.setter.TextEditor" p:spellChecker-ref="spellChecker">
   </bean>

   <bean id="spellChecker" class="com.tutorialspoint.di.setter.SpellChecker"/>

</beans>
原文地址:https://www.cnblogs.com/sysman/p/4479951.html