7.3 Spring 的核心机制 : 依赖注入

      Spring 框架的核心功能有两个。

        Spring容器作为超级大工厂,负责创建、管理所有的Java对象,这些Java对象被称为Bean。

        Spring容器管理容器中Bean之间的依赖关系,Spring使用一种被称为“依赖注入”的方式来管理Bean之间的依赖关系。

      7.3.1 理解依赖注入

        当某个java对象需要调用另一个Java对象的方法时,在传统模式下通常有如下两种做法:

        1. 原始做法 : 调用者主动创建被依赖对象,然后在调用被依赖对象的方法。

        2. 简单工厂模式 : 调用者先找到被依赖对象的工厂,然后主动通过工厂去获取被依赖对象,最后在调用被依赖对象的方法。

        解1:由于调用者需要通过形如“new Person()”的代码创建对象,因此必然导致调用者与被依赖对象实现类的硬编码耦合,非常不利于项目升级的维护。

        解2:对于简单工厂的方式,大致需要把握三点:①调用者面向被依赖对象的接口编程;②将被依赖对象的创建交给工厂完成;③调用者通过工厂来获得被依赖组件。调用者只需与被依赖对象的接口耦合,避免了类层次的硬编码耦合。缺点:调用组件需要主动通过工厂去获取被依赖对象,这就会带来调用组件与被依赖对象工厂的耦合。

        使用Spring框架的两个主要改变是:

          程序无须使用 new 调用构造器去创建对象。所有的Java对象都可交给 Spring 容器去创建。

          当调用者需要调用被依赖对象的方法时,调用者无须主动获取被依赖对象,只要等待 Spring 容器注入即可。

        依赖注入通常有两种:

          设值注入 :  IoC 容器使用成员变量的setter方法来注入被依赖对象。

          构造注入 :  IoC 容器使用构造器来注入被依赖对象。

      7.3.2 设值注入

        设值注入是指IoC容器通过成员变量的setter方法来注入被依赖对象。

        Spring 推荐面向接口编程。不管是调用者,还是被依赖对象,都应该为之定义接口,程序应该面向它们的接口,而不是面向实现类编程,这样以便程序后期的升级、维护。

        Spring 推荐面向接口编程,这样可以更好地让规范和实现分离,从而提供更好的解耦。对于一个Java  EE应用,不管是DAO组件,还是Service组件,都应该先定义一个接口,该接口定义了该组件应该实现的功能,但功能的实现则由实现类提供。

        Interface : Person

package edu.pri.lime._7_3_2.bean;

//定义Person对象应遵守的规范
public interface Person { // 定义一个使用斧头的方法
public void useAxe(); }

        Interface :Axe

package edu.pri.lime._7_3_2.bean;

//定义Axe对象应遵守的规范
public interface Axe { // Axe 接口中定义一个chop()方法
public String chop();
}

        Class :Chinese

package edu.pri.lime._7_3_2.bean.impl;

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

        Class : StoneAxe

package edu.pri.lime._7_3_2.bean.impl;

import edu.pri.lime._7_3_2.bean.Axe;

public class StoneAxe implements Axe {

    public String chop() {
// TODO Auto-generated method stub
return "石斧砍柴好慢";
} }

        配置文件

<?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的Bean。其实现类是edu.pri.lime._7_3_2.bean.impl.Chinese类 -->
<bean id="person" class="edu.pri.lime._7_3_2.bean.impl.Chinese">
<!-- 驱动调用chinese的setAxe()方法,将容器中的stoneAxe Bean 作为传入参数 -->
<property name="axe" ref="stoneAxe"/>
</bean> <!-- 配置名为StoneAxe的Bean,其实现类是edu.pri.lime._7_3_2.bean.impl.StoneAxe类 -->
<bean id="stoneAxe" class="edu.pri.lime._7_3_2.bean.impl.StoneAxe"/> </beans>

        Class : TestBean

package edu.pri.lime._7_3_2.mian;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import edu.pri.lime._7_3_2.bean.Person;
import edu.pri.lime._7_3_2.bean.impl.Chinese; public class BeanTest { public static void main(String[] args){
// 创建Spring容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_3_2.xml");
// 获取chinese 实例
Person per = ctx.getBean("chinese", Chinese.class);
// 调用 useAxe()方法
per.useAxe();
}
}

        Class : SteelAxe

package edu.pri.lime._7_3_2.bean.impl;

import edu.pri.lime._7_3_2.bean.Axe;

public class SteelAxe implements Axe {

    public String chop() {
// TODO Auto-generated method stub
return "钢斧砍柴真快";
} }

        Class : TestBean

package edu.pri.lime._7_3_2.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import edu.pri.lime._7_3_2.bean.Person;
import edu.pri.lime._7_3_2.bean.impl.Chinese; public class BeanTest { public static void main(String[] args){
//创建Spring容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_3_2.xml");
//获取chinese 实例
Person per = ctx.getBean("chinese", Chinese.class);
//调用 useAxe()方法
per.useAxe(); Person chi = ctx.getBean("china",Chinese.class);
chi.useAxe();
}
}

        Spring IoC 容器的三个基本要点:

          应用程序的各组件面向接口编程。面向接口编程可以将组件之间的耦合关系提升到接口层次,从而有利于项目后期的扩展。

          应用程序的各组件不再由程序主动创建,而是有Spring容器来负责产生并初始化。

          Spring 采用配置文件或注解来管理 Bean 的实现类、依赖关系,Spring容器则根据配置文件或注解,利用反射来创建实例,并为之注入依赖关系。

      7.3.3 构造注入

        在构造实例时,已经为其完成依赖关系的初始化,这种利用构造器来设置依赖关系的方式,被称为构造注入。

        驱动Spring 在底层以反射方式执行带指定参数的构造器,当执行带参数的构造器时,就可利用构造器参数对成员变量执行初始化------这就是构造注入的本质。

        <bean.../> 元素默认驱动Spring调用无参数的构造器来创建对象。使用<constructor-arg.../>子元素代表一个构造器参数,如果<bean.../>元素包含N个<contructor-arg.../>子元素,就会驱动Spring调用带N个参数的构造器来创建对象。

        Class :Chinese

package edu.pri.lime._7_3_3.bean.impl;

import edu.pri.lime._7_3_2.bean.Axe;
import edu.pri.lime._7_3_2.bean.Person; public class Chinese implements Person { private Axe axe; public Chinese() {
super();
// TODO Auto-generated constructor stub
} // 未有setter()方法,使用构造方法注入
public Chinese(Axe axe) {
super();
this.axe = axe;
} public void useAxe() {
System.out.println(axe.chop());
} }

        配置文件 :

<?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的Bean。其实现类是edu.pri.lime._7_3_3.bean.impl.Chinese类 -->
<bean id="chinese" class="edu.pri.lime._7_3_3.bean.impl.Chinese">
<!-- 驱动Spring调用Chinese的带一个参数的构造器来创建对象 -->
<constructor-arg ref="stoneAxe"/>
</bean> <!-- 配置名为StoneAxe的Bean,其实现类是edu.pri.lime._7_3_2.bean.impl.StoneAxe类 -->
<bean id="stoneAxe" class="edu.pri.lime._7_3_2.bean.impl.StoneAxe" /> <bean id="steelAxe" class="edu.pri.lime._7_3_2.bean.impl.SteelAxe"/>
</beans>

        Class : BeanTest

package edu.pri.lime._7_3_3.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import edu.pri.lime._7_3_2.bean.Person;
import edu.pri.lime._7_3_3.bean.impl.Chinese; public class BeanTest { public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_3_3.xml");
Person per = ctx.getBean("chinese",Chinese.class);
per.useAxe();
}
}

        Spring底层,反射机制

        String idStr = ... // Spring 解析<bean.../> 元素得到id属性值为chinese
String refStr = ... // Spring 解析 <constructor-arg.../> 元素得到ref属性值为steelAxe
Object paramBean = container.get(refStr);
// Spring 会用反射方式执行下面代码(仅仅示例,为用反射)
Object obj = new Chinese(paramBean);
// container 代表Spring 容器
container.put(idStr,obj);
package edu.pri.lime._7_3_3.main;

import java.lang.reflect.Constructor;

import edu.pri.lime._7_3_2.bean.Axe;
import edu.pri.lime._7_3_2.bean.Person; public class ReflectTest { public static void main(String[] args) throws Exception{
Class<?> clazzChi = Class.forName("edu.pri.lime._7_3_3.bean.impl.Chinese");
Class<?> clazzAxe = Class.forName("edu.pri.lime._7_3_2.bean.impl.SteelAxe");
Class<?> clazz = Class.forName("edu.pri.lime._7_3_2.bean.Axe");
Axe axe = (Axe) clazzAxe.newInstance();
Constructor<?> con = clazzChi.getConstructor(clazz);
Person per = (Person) con.newInstance(axe);
per.useAxe();
}
}

        配置<constructor-arg .../> 元素是可指定一个index属性,用于指定该构造参数值将作为第几个构造参数数值:index=0表明该构造参数值将作为第一个构造参数值。

        <constructor-arg value="23" type="int"/>:用于更明确的指定数据类型。

      7.3.4  两种注入方式的对比

        

7 -- Spring的基本用法 -- 3... Spring 的核心机制 : 依赖注入的更多相关文章

  1. Spring的核心机制——依赖注入(Dependency Inject)

    Spring不仅提供对象,还提供对象的属性值,而不是由使用该对象的程序所提供的. Java应用是由一些相互协作的对象所组成的,在Spring中这种相互协作的关系就叫依赖关系. 如果A组件调用了B组件的 ...

  2. Spring的核心机制——依赖注入(Dependency Inject)

    Spring不仅提供对象,还提供对象的属性值,而不是由使用该对象的程序所提供的. Java应用是由一些相互协作的对象所组成的,在Spring中这种相互协作的关系就叫依赖关系. 如果A组件调用了B组件的 ...

  3. Spring的核心机制依赖注入

    原文地址:http://developer.51cto.com/art/200610/33311.htm 本文主要讲解依赖注入(设值注入.构造注入),作用是可以使Spring将各层的对象以松耦合的方式 ...

  4. spring-第一篇之spring核心机制依赖注入(DI)/控制翻转(IoC)

    1.spring的核心机制:依赖注入(DI)/控制翻转(IoC) 什么是依赖:A对象需要调用B对象,所以A依赖于B. 什么是注入:A对象注入一个属性B对象. 什么是依赖注入(DI):A对象依赖于B对象 ...

  5. 【Spring Framework】Spring 入门教程(一)控制反转和依赖注入

    参考资料 Spring 教程 说在前面 什么样的架构,我们认为是一个优秀的架构? 判断准则:可维护性好,可扩展性好,性能. 什么叫可扩展性好? 答:在不断添加新的代码的同时,可以不修改原有代码,即符合 ...

  6. 7 -- Spring的基本用法 -- 5... Spring容器中的Bean;容器中Bean的作用域;配置依赖;

    7.5 Spring容器中的Bean 7.5.1 Bean的基本定义和Bean别名 <beans.../>元素是Spring配置文件的根元素,该元素可以指定如下属性: default-la ...

  7. Spring源码解析三:IOC容器的依赖注入

    一般情况下,依赖注入的过程是发生在用户第一次向容器索要Bean是触发的,而触发依赖注入的地方就是BeanFactory的getBean方法. 这里以DefaultListableBeanFactory ...

  8. 一) Spring 介绍、IOC控制反转思想与DI依赖注入

    一.spring介绍1.IOC反转控制思想(Inversion of Control)与DI依赖注入(Dependency Injection)2.AOP面向切面的编程思想与动态代理3.作用:项目的粘 ...

  9. spring(一、原理、IOC、AOP、依赖注入)

    1.spring原理 内部最核心的就是IOC了,动态注入,让一个对象的创建不用new了,可以自动的生产,这其实就是利用java里的反射,反射其实就是在运行时动态的去创建.调用对象,Spring就是在运 ...

随机推荐

  1. solr中时区处理

    solr.in.sh中的最后 # By default the start script uses UTC; override the timezone if needed SOLR_TIMEZONE ...

  2. LeetCode: Surrounded Regions 解题报告

    Surrounded Regions Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'. A ...

  3. git 分支管理 推送本地分支到远程分支等

    1.创建本地分支 local_branch git branch local_branch 2.创建本地分支local_branch 并切换到local_branch分支 git checkout - ...

  4. Java面试知识1

    JAVA面试题集 基础知识: 1.C++或Java中的异常处理机制的简单原理和应用.     当JAVA程序违反了JAVA的语义规则时,JAVA虚拟机就会将发生的错误表示为一个异常.违反语义规则包括2 ...

  5. JAVA培训资料

    JAVA培训资料 一.Java语言 1.面向对象的三个基本特征 2.方法重载和方法重写的概念和区别 3.接口和内部类.抽象类的特性 4.文件读写的基本类 **5.串行化的注意事项以及如何实现串行化 6 ...

  6. 一站式学习Wireshark(十):应用Wireshark显示过滤器分析特定数据流(下)

    介绍 掌握显示过滤器对于网络分析者来说是一项必备的技能.这是一项大海捞针的技巧.学会构建,编辑,保存关键的显示过滤器能够节省数小时的时间. 与捕捉过滤器使用的BPF语法不同,显示过滤器使用的是Wire ...

  7. 补充下.net知识

    问题1: public int getvalue(int a) { try { a = a + ; ; } catch (Exception) { throw; } finally { a = a + ...

  8. IS支持解析json

    1. MIME设置:在IIS的站点属性的HTTP头设置里,选MIME 映射中点击”文件类型”-”新类型”,添加一个文件类型:关联扩展名:*.json内容类型(MIME):application/x-j ...

  9. d3js技术文档

      D3js技术文档 概述 D3 allows you to bind arbitrary data to a Document Object Model (DOM), and then apply ...

  10. ThinkPHP3.2 分组分模块

    ThinkPHP/Conf/convention.php 'CONTROLLER_LEVEL'      =>  1, 修改成 'CONTROLLER_LEVEL'      =>  2,