每个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中依赖注入的方式有两种:
- 通过bean的构造器参数进行注入
- 通过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.运行程序,检查结果:
constructor-arg元素还包含其他一些属性,如下:
可能保持独立,因为这样更容易做到代码的重用,也有利于单元测试的开展.spring的依赖注入功能能在保持类相互独立