Spring依赖注入

Spring框架的核心功能有两个,Spring容器作为超级工厂,负责创建、管理所有的Java对象,这些Java对象被称为Bean;Spring容器管理容器中Bean之间的依赖关系,Spring使用一种被称为:“依赖注入”的方式来管理Bean之间的依赖关系。

当某个Java实例(调用者)需要另一个Java实例(被调用者)时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。

在依赖注入的模式下,创建被调用者的工作不再由调用者完成,因此称为控制反转(Inversion of Control,IoC);创建被调用者实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。

1、理解依赖注入

当编写一个复杂的Java应用程序时,应用程序类应该尽可能独立于其他Java类来增加这些类重用的可能性,且在做单元测试时,测试独立于其他类的独立性。依赖注入有助于把这些类黏合在一起,同时保持它们的独立性。
假设有一个包含文本编辑器组件的应用程序,并要提供拼写检查功能。其代码如下:

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

在这里需要创建TextEditor和SpellChecker之间的依赖关系。在控制反转的场景下,反而会做这样的事情:

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

TextEditor不应该担心SpellChecker的实现。SpellChecker将会独立实现,并且在TextEditor实例化的时候将提供给TextEditor,整个过程是由Spring框架控制的。
我们已经从TextEditor中删除了全面控制,并且把它保存到其他地方(XML配置文件),且依赖关系通过类构造函数被注入到TextEditor类中。因此,控制流通过依赖注入已经“反转”,因为已经有效地委托了依赖关系到一些外部系统。

依赖注入一般可以分为3种方式:构造器注入、setter注入和接口注入。构造器注入和setter注入是主要方式,而接口注入则意味着注入的内容来自外界,例如,在Web应用中,配置的数据源是在Tomcat服务器的context.xml文件中配置的,并以JNDI的形式通过接口将它注入Spring IoC容器中。
setter注入(设值注入)是指IoC容器通过成员变量的setter方法来注入被依赖对象。这种注入方式简单、直观,因而在Spring的依赖注入中被大量使用。
利用构造器来设置依赖关系的方式,被称为构造器注入。通俗来说,就是驱动Spring在底层以反射方式执行带指定参数的构造器,当执行带参数的构造器时,即可利用构造器参数对成员变量执行初始化,这就是构造器注入的本质。

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

(1)AccountDaoImol.java的主要代码如下:

public class AccountDaoImpl implements AccountDao {
	@Override
	public void add() {
		System.out.println("save account...");
	}
}

(2)AccountServiceImol.java的主要代码如下:

public class AccountServiceImpl implements AccountService {
//添加AccountDao属性的setter方法,用于实现依赖注入
	public void setAccountDao(AccountDao accountDao){
		this.accountDao = accountDao;
	}
	@Override
	public void addAccount() {
		this.accountDao.add();
		System.out.println("account added!");
	}
}

(3)在Spring配置文件ApplicationContext.xml中添加如下内容:

<bean id="accountDaoInstance"
	class="com.mialab.SpringBasicDemo1.dao.impl.AccountDaoImpl"/>
<bean id="accountService"
    class="com.mialab.SpringBasicDemo1.service.impl.AccountServiceImpl">
    <!--将id为accountDao的Bean实例注入accountService实例中-->
    <property name="accountDao" ref="accountDaoInstance"/>
</bean>

(4)测试类TestDI_1.java的主要代码如下:

public class TestDI_1 {
	public static void main(String[] args){
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		AccountService accountService = (AccountService)applicationContext.getBean("accountService");
		accountService.addAccount();
	}
}

运行测试类TestDI_1的main()方法,控制台上将有一下输出:

save account...
account added!

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

(1)AccountServiceImpl_2.java的主要代码如下:

public class AccountServiceImpl_2 implements AccountService {
	private AccountDao accountDao;
	public AccountServiceImpl_2(AccountDao accountDao){
		System.out.println("Inside AccountServiceImpl_2 constructor.");
		this.accountDao = accountDao;
	}
	@Override
	public void addAccount() {
		System.out.println("account added again!");
	}
}

(2)在Spring配置文件ApplicationContext2.xml中添加如下内容:

<bean id="accountDao2"
	class="com.mialab.SpringBasicDemo1.dao.impl.AccountDaoImpl"/>
<bean id="accountService2"
    class="com.mialab.SpringBasicDemo1.service.impl.AccountServiceImpl_2">
  <constructor-arg ref="accountDao2"/>
</bean>

(3)测试类TestDI_2.java的主要代码如下:

public class TestDI_2 {
	public static void main(String[] args){
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext2.xml");
		AccountService accountService2 = (AccountService)applicationContext.getBean("accountService2");
		accountService2.addAccount();
	}
}

(4)运行测试类TestDI_2的main()方法,控制台上将有一下输出:

Inside AccountServiceImpl_2 constructor.
save account...
account added again!

两种注入方式的对比

设值注入有如下优点:

  • 与传统的JavaBean的写法更相似,程序开发人员更容易理解、接受。通过setter方法设定依赖关系显得更加直观、自然。
  • 对于复杂的依赖关系,如果财通构造柱如,会导致构造器过于臃肿,难以阅读。Spring在创建Bean实例时,需要同时实例化其依赖的全部实例,因而导致性能下降。而使用设值注入能避免这些问题。
  • 在某些成员变量可选的情况下,多参数的构造器更加笨重。

构造注入有如下优点:

  • 构造注入可以在构造器中决定依赖关系的注入顺序,优先依赖的优先注入。
  • 对于依赖关系无须变化的Bean,构造注入更有用处。因而没有setter方法,所有的依赖关系全部在构造器内设定,无须担心后续代码对依赖关系产生破坏。
  • 依赖关系智能在构造器中设定,则只有组件的创建者才能改变组件的依赖关系,对组件的调用者而言,组件内部的依赖关系完全透明,更符合高内聚的原则。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值