依赖注入的概念

如果要在一个类中,使用另一个类,传统的方式是直接new:

class  A{

  //......

  B  b=new B();

  //......

}

A类对象依赖于B类对象,如果没有B类对象,A类对象就不能正常工作,称为A依赖B。

上面的方式会增加A类与B类的耦合,不利于项目后期的升级(扩展)、维护。

在Spring中,B类的实例(被调用者),不再由A类(调用者)创建,而是由Spring容器创建,创建好以后,由Spring容器将B类实例注入A类实例中,称为依赖注入(Dependency Injection,DI)。

原本是由A类主动创建B类对象(A类控制B类的创建),现在是Spring容器创建B类对象,注入A类对象中,A类被动接受Spring容器创建的B类实例,B类对象创建的控制权发生了反转,所以又叫做控制反转(Inversion of Control,IoC)。

控制反转(IoC)是由依赖注入(DI)实现的,依赖注入又是由spring容器实现的,所以Spring容器又叫做Spring  IoC容器。。

依赖注入是一种优秀的解耦方式,由Spring容器负责控制类(Bean)之间的关系,降低了类之间的耦合。

常用的方式有2种:

  • 设值注入,也叫set方式注入
  • 构造方法注入

设值注入

将依赖作为成员变量,通过主调类的setter方法注入依赖。

public class A {
private B b; public void setB(B b) {
this.b = b;
} //......
}

xml配置:

    <bean name="b" class="com.chy.bean.B" />
<bean name="a" class="com.chy.bean.A">
<property name="b" ref="b"/>
</bean>

使用<property>注入依赖,name指定属性名(成员变量名),ref指定要注入的bean(value指定要注入的常量值)。

如果要注入多个依赖,使用多个<property />即可。


构造方法注入

将依赖作为成员变量,通过主调类的构造方法注入依赖。

public class A {
private B b; public A(B b) {
this.b = b;
} //......
}

xml配置:

<bean name="b" class="com.chy.bean.B" />
<bean name="a" class="com.chy.bean.A">
<constructor-arg name="b" ref="b" />
</bean>

一个<constructor-arg />注入一个参数,name指定构造方法中的形参名,ref指定要注入的bean(value指定要注入的常量值)。

形参可用 name="形参名" 指定,也可以使用 index="形参表下标" 来指定(第一个参数 => 下标0)。

如果有多个形参,使用多个<constructor-arg />即可,spring会调用对应的构造方法。


不管是设值注入,还是构造方法注入,都是将依赖作为成员变量,所以有时候也把注入依赖叫做注入属性。


依赖可分为3种类型:

  • 注入int、float、String之类的基本数据类型,使用value。

比如根据学号查学生信息,需要注入一个int型的学号。

spring会自动将值转换为需要的类型,比如需要的String,value="chy"会以String的形式注入。value="1",如果需要的是int,就转换为int注入,如果需要的是String,就转换为String注入。

  • 注入其他Bean的实例,使用ref。
  • 注入数组、集合、Properties等复杂类型

注入复杂类型的依赖

将复杂类型的数据数据作为成员变量:

    private Object[] arr;
private List<Object> list;
private Set<Object> set;
private Map<String,Object> map;
private Properties properties;

设值注入需提供对应的setter方法,构造方法注入需提供对应的构造方法。

设值注入:

 <bean name="a" class="com.chy.bean.A">
<!-- 注入数组-->
<property name="arr">
<array>
<!-- 基本数据类型使用value,bean的实例使用ref,可嵌套其他复杂类型-->
<value>chy</value>
<ref bean="b" />
</array>
</property> <!-- 注入List -->
<property name="list">
<list>
<value>chy</value>
<ref bean="b" />
</list>
</property> <!-- 注入Set -->
<property name="set">
<set>
<value>chy</value>
<ref bean="b" />
</set>
</property> <!-- 注入Map-->
<property name="map">
<map>
<!-- Map的key只能是String,基本数据类型用value,其他Bean的实例用value-ref -->
<entry key="id" value="1" />
<entry key="user" value-ref="b" />
</map>
</property> <!-- 注入Properties -->
<property name="properties">
<props>
<!-- 键、值都只能是String -->
<prop key="username">chy</prop>
<prop key="password">abcd</prop>
</props>
</property>
</bean>

<property name="">  name指定属性名(成员变量名)。

数组、List、Set的配置方式是差不多的。

构造方法注入:

<constructor-arg name="arr">
<array>
<value>chy</value>
<ref bean="b" />
</array>
</constructor-arg>

配置方式和设值注入差不多,只不过将 property 换为 constructor-arg ,name是指定形参名。

用的最多的是设值注入,因为很多时候都要修改成员变量的值,setter方法一般都要写,直接用setter方法设值注入,没必要再写带参的构造方法。


使用自动装配注入其它Bean的实例

原先注入其它bean的实例,需要使用<property />或<constructor />注入。

使用自动装配后,不需要使用<property />、<constructor />,spring会自动在容器中找到满足要求的其它bean,注入进来。

<bean name="a" class="com.chy.bean.A" autowire="byName" />

可选的值:

  • no   默认值,不使用自动装配,如果要注入其它bean的实例,需要使用<property />或<constructor />。
  • byName   根据name来自动装配
  • byType  根据type来自动装配
  • constructor  根据构造函数形参类型进行byType方式的自动装配
  • default   使用全局默认的自动装配方式。

byName和byType都能在设值注入中使用,constructor只能在构造方法注入中使用。

byName

public class A {
private B b; public void setB(B b) {
this.b = b;
}
}
<bean name="b" class="com.chy.bean.B" />
<bean name="a" class="com.chy.bean.A" autowire="byName" />

A依赖B,A中有对应的setter方法。

byName,name就是setter方法的方法名,去掉set,后面部分使用camel写法,比如setB() =>  b,

spring会自动到容器中找到name="b"的bean,注入。

name="b"的bean只能有一个,不然spring不知道要注入哪个。

byType

和byName差不多,也是要配合setter方法使用。不同的是:

byType,type是形参表的参数类型。比如setB(B  b),参数类型是B,Spring自动找到class=“B”的bean,注入。

class=“B”的bean只能有一个,不然spring不知道要注入哪个。

constructor

public class A {
private B b; public A(B b) {
this.b = b;
}
}

顾名思议,需要和构造方法注入搭配使用。

找到带参的构造器,根据参数类型,按照byType的方式注入依赖。

default

使用全局默认的自动装配方式。

<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"
default-autowire="byName"> <bean name="b" class="com.chy.bean.B" />
<bean name="a" class="com.chy.bean.A" autowire="default" />
</beans>

需要在根元素<beans>中设置全局默认的自动装配方式,所有default方式的自动装配都是使用 default-autowire 设置的方式进行装配。

自动装配的贪婪原则

自动装配会尽量多地注入依赖。

比如constructor ,有2个构造方法:(B b)、(B b, C c),如果容器中有B、C的实例,则优先调用(B b, C c),会尽量多地注入依赖。

自动装配的优点:一个属性就搞定,不必写大量的<property />或<constructor />。

缺点:自动装配只能注入其它bean的实例,使用时有限制条件。(可以和注入基本类型、复杂类型的方式一起使用。实际上,注入基本类型、bean的实例、复杂类型都可以搭配使用。)


使用SpEL注入依赖

SpEL,即Spring Expression Language,spring表达式语言。

使用SpEL可以注入基本类型,可以注入其它Bean,可以访问其它Bean的成员变量、调用其它Bean中的方法。

使用示例:

    <bean name="score" class="com.chy.bean.Score">
<property name="chinese" value="#{90}" />
<property name="math" value="#{100}" />
<property name="english" value="#{95}" />
</bean>
<bean name="student" class="com.chy.bean.Student">
<property name="no" value="#{1}" />
<property name="name" value="#{'chy'}" />
<property name="score" value="#{score}" />
</bean>

SpEL放在#{ }中,数值型直接写,字符、字符串要加单引号,可以直接引用其它Bean。

SpEL使用的是设值注入,所以需要提供setter方法,只能用<property />注入值,不能使用构造方法注入。

不管值是什么类型,都只能用value,不能用ref。

可以直接访问其它Bean的成员变量,比如 #{score.math} ,实质是调用对应的getter方法,所以需要提供getter方法。

可以调用其它Bean的方法,比如 #{score.getMath()},如果该方法返回void,作为null处理。

Spring的核心机制:依赖注入的更多相关文章

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

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

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

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

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

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

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

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

  5. 7 -- Spring的基本用法 -- 3... Spring 的核心机制 : 依赖注入

    7.3 Spring 的核心机制 : 依赖注入 Spring 框架的核心功能有两个. Spring容器作为超级大工厂,负责创建.管理所有的Java对象,这些Java对象被称为Bean. Spring容 ...

  6. Spring源码剖析依赖注入实现

    Spring源码剖析——依赖注入实现原理 2016年08月06日 09:35:00 阅读数:31760 标签: spring源码bean依赖注入 更多 个人分类: Java   版权声明:本文为博主原 ...

  7. 回客科技 面试的 实现ioc 容器用到的技术,简述BeanFactory的实现原理,大搜车面试的 spring 怎么实现的依赖注入(DI)

    前言:这几天的面试,感觉自己对spring 的整个掌握还是很薄弱.所以需要继续加强. 这里说明一下spring的这几个面试题,但是实际的感觉还是不对的,这种问题我认为需要真正读了spring的源码后说 ...

  8. AspNet Core 核心 通过依赖注入(注入服务)

    说起依赖注入 相信大家已经很熟悉了,这里我在简要的描述一遍, 什么是依赖注入: 我们从字面意义上来解释一下:依赖代表着两个或者多个对象之间存在某些特定的联系:举一个不是很恰当的例子 比如说一度夫妻组成 ...

  9. Spring quartz Job不能依赖注入,Spring整合quartz Job任务不能注入

    Spring quartz Job不能依赖注入,Spring整合quartz Job任务不能注入 Spring4整合quartz2.2.3中Job任务使用@Autowired不能注入 >> ...

  10. spring 控制反转与依赖注入原理-学习笔记

    在Spring中有两个非常重要的概念,控制反转和依赖注入:控制反转将依赖对象的创建和管理交由Spring容器,而依赖注入则是在控制反转的基础上将Spring容器管理的依赖对象注入到应用之中: 所谓依赖 ...

随机推荐

  1. H3C交换机如何删除VLAN

    H3C交换机如何删除VLAN,如果直接使用“undo vlan”是删不干净的,因为配置VLAN时还配置过接口. 1.首先通过console口或telnet连接三层交换机,进入用户视图模式”<H3 ...

  2. Xamarin.FormsShell基础教程(2)创建Shell解决方案

    Xamarin.FormsShell基础教程(2)创建Shell解决方案 创建Shell解决方案 在开发Shell的应用程序时,首先需要创建一个Shell解决方案,其具体操作步骤如下: (1)在VS的 ...

  3. 【PHP】使用phpoffice/phpspreadsheet导入导出数据

    当你在使用phpoffice/phpexcel 类库时候.composer 会给你提示一句话 Package phpoffice/phpexcel is abandoned, you should a ...

  4. matlab学习笔记12_3串联结构体,按属性创建含有元胞数组的结构体,filenames,isfield,isstruct,orderfields

    一起来学matlab-matlab学习笔记12 12_3 结构体 串联结构体,按属性创建含有元胞数组的结构体,filenames,isfield,isstruct,orderfields 觉得有用的话 ...

  5. chrome 报错 ERR_CERT_AUTHORITY_INVALID

    场景: 本地调试https/wss程序,使用了openssl自签名的证书,解决方法:添加到信任证书 根据以下图片流程操作 然后 打开selfsigned.cer 清空该网站缓存 参考资料: https ...

  6. Windows10 下安装 oracle 客户端,安装 plsql 破解并实现汉化

    一,软件准备 1,win10 操作系统 2,oracle_11g_r2 client 这里是 64 位的软件  3, plsql 11.0.6 这里我们下载 64 的,32 位操作系统现在已经很少了, ...

  7. 使用BaGet 搭建私有nuget 服务器

    使用BaGet 搭建私有nuget 服务器 netNugetBaGet 引言 为了增强代码的安全性和企业团队开发的高效性,搭建私有的package 包管理服务器是很有必要的,搭建私有的类库管理服务有以 ...

  8. Node 脚本的调试工具

    2016年,Node 决定将 Chrome 浏览器的"开发者工具"作为官方的调试工具,使得 Node 脚本也可以使用图形界面调试 1.准备 创建目录 D:\nodejs>mk ...

  9. git中配置的.gitignore不生效的解决办法

    通常我们希望放进仓库的代码保持纯净,即不要包含项目开发工具生成的文件,或者项目编译后的临时文件.但是,当我们使用git status查看工作区状态的时候,总会提示一些文件未被track.于是,我们想让 ...

  10. ActiveMQ 安装方法

    1. 打开浏览器,访问网址 http://activemq.apache.org/components/classic/download/ ,下载最新的版本,当前最新版本为5.15.9,根据Activ ...