您的位置:首页 > 编程语言 > Java开发

Spring的学习(三):核心机制:依赖注入

2017-08-24 00:00 344 查看

1、前言

Java应用中经常存在对象A调用对象B方法的情况,这种情况被spring称作依赖,即为A对象依赖B对象。对于java应用来说,它们总是由一些互相调用的对象构成的,Spring把这种调用关系称作依赖关系。若A组件调用了B的方法,称作A组件依赖B组件。
Spring框架的核心功能有两个:

spring容器作为超级工厂,负责创建、管理所有的Java对象,这些Java对象被称为bean;

spring 容器使用依赖注入的方式来管理容器中Bean之间的依赖关系

2、理解依赖注入

控制反转(IOC):调用者获取被依赖对象的方式由原来的主动获取变为现在的被动接受;

依赖注入(DI):spring容器负责将被依赖对象赋值给调用者的成员变量,相当于为调用者注入它依赖的实例;
依赖注入通常有两种:

设值注入:IOC容器使用成员变量的setter方法来注入被依赖对象。Bean与Bean之间的依赖关系由Spring管理,Spring采用setter方法为目标Bean注入所依赖的Bean;

构造注入:IOC容器使用构造器来注入被依赖对象;

2.1、设值注入

spring推荐面向接口编程,可以更好的让规范和实现分离,从而实现更好的解耦。在JavaEE中,不管是DAO组件还是业务逻辑组件,都应该先定义一个接口,定义了该接口实现的功能,但功能的实现由实现类提供。

(1)、先定义一个person接口

package org.crazyit.app.service;
public interface Person{
//定义一个使用斧头的方法
public void useAxe();
}

(2)、再定义一个Axe接口

package org.crazyit.app.service;

public interface Axe {
//定义一个砍的方法
public String chop();
}

(3)、Person类的实现代码

package org.crazyit.app.service.impl;

import org.crazyit.app.service.Axe;
import org.crazyit.app.service.Person;

public class Chinese implements Person{
private Axe axe;
//设值注入所需要的setter方法
public void setAxe(Axe axe){
this.axe = axe;
}
// 实现Person接口的useAxe方法
public void useAxe() {
//调用axe的chop方法
//表明person对象依赖与axe对象
System.out.println(axe.chop());
}
}

此时,Chinese类不知道它调用的Axe实例在哪,也不知道Axe实例是怎么实现的,它只需要调用Axe实例的方法即可。Axe实例由spring容器负责注入。

(4)、Axe的实现类如下:

package org.crazyit.app.service.impl;

import org.crazyit.app.service.Axe;

public class StoneAxe implements Axe{

@Override
public String chop() {
return "石斧砍柴好慢!";
}

}

程序依然不知道Chinese类和哪个Axe实例耦合,这是就需要Spring使用XML文件来指定实例之间的依赖关系

(5)、配置文件beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--  Spring配置文件的根元素,使用spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <!-- 配置chinese实例,其实现类是Chinese类 -->
<bean id="chinese" class="org.crazyit.app.service.impl.Chinese">
<!--  驱动调用chinese的setAxe()方法,将容器中stoneAxe作为传入参数  -->
<property name="axe" ref="stoneAxe"/>
</bean>
<!-- 配置stoneAxe实例,其实现类是StoneAxe -->
<bean id="stoneAxe" class="org.crazyit.app.service.impl.StoneAxe"/>
</beans>

Spring配置Bean实例通常会指定两个属性:

id :这是指定该Bean的唯一标识。Spring通过id属性值来管理该Bean之间的依赖,程序通过它来访问该Bean的实例;

class:指定该Bean的实现类,这时候不能再用接口,必须为其实现类。Spring会使用XML解析器来读取该属性值,并利用反射来创建该实现类的实例;

<property>是<bean>的子元素,它驱动spring在底层以反射方式来执行一次setter方法。name属性决定执行那个setter方法,value和ref决定执行setter方法的执行参数。

如果传入参数是基本类型及其包装类、String等类型,用value属性指定传入参数;

如果以容器中其他Bean类型作为传入参数,则用ref;

(6)、主程序代码BeanTest.java

package lee;

import org.crazyit.app.service.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanTest {

public static void main(String[] args) throws Exception {
//创建spring容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
//获取person实例
Person p = ctx.getBean("chinese", Person.class);
//调用useAxe方法
p.useAxe();
}
}

run as后得到



(7)、文件目录示意图



2.2、构造注入

本质:驱动Spring在底层以反射方式执行带指定参数的构造器,此时,可以利用构造器参数对成员变量执行初始化;

(1)、修改上面的Chinese类

package org.crazyit.app.service.impl;

import org.crazyit.app.service.Axe;
import org.crazyit.app.service.Person;

public class Chinese implements Person{
private Axe axe;
//构造注入所需的带参数的构造器
public Chinese (Axe axe){
this.axe = axe;
}
// 实现Person接口的useAxe方法
public void useAxe() {
//调用axe的chop方法
//表明person对象依赖与axe对象
System.out.println(axe.chop());
}
}

(2)、修改配置文件
<bean>默认驱动Spring调用无参的构造器来创建对象,也可以使用<constrctor-arg../>子元素来驱动Spring调用有参数的构造器来创建对象。每个<constrctor-arg../>子元素代表一个构造器参数。

把上面的beans.xml修改如下:

<?xml version="1.0" encoding="UTF-8"?>
<!--  Spring配置文件的根元素,使用spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <!-- 配置chinese实例,其实现类是Chinese类 -->
<bean id="chinese" class="org.crazyit.app.service.impl.Chinese">
<!--  下面只有一个constructor-arg子元素,驱动spring调用Chinese带一个参数的构造器来创建对象  -->
<constructor-arg ref="stoneAxe"/>
</bean>
<!-- 配置stoneAxe实例,其实现类是StoneAxe -->
<bean id="stoneAxe" class="org.crazyit.app.service.impl.StoneAxe"/>
</beans>

2.3、区别

比如在此例中,就是创建Person实例中Axe属性的时机不同

设置注入是先通过调用无参数的构造器来创建一个Bean实例,然后调用对应的setter方法来进行注入依赖关系

构造注入是直接调用有参数的构造器,当Bean实例创建完成后,也完成了依赖关系的注入
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: