Srping - bean的依赖注入(Dependency injection)
目录
1 概述
这篇文章主要就是讲解Spring的bean之间依赖注入的方法,本文不讲原理,只涉及用法。
在实际项目中,我们常常需要在一个bean中引用另外一个bean,例如业务逻辑处理(service)层调用数据处理(dao)层。那么就有了依赖注入(Dependency Injection),简称DI。
2 两种基本的依赖注入方式
Spring提供了2种基本方式让我们实现DI,分别是通过构造函数和setter方法。下面我们来一一介绍。
2.1 构造函数方式
实现方式如下:
java代码:
package x.y;
public class Foo {
public Foo(Bar bar, Baz baz) {
// ...
}
}
bean配置:
<beans>
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
</bean> <bean id="bar" class="x.y.Bar"/>
<bean id="baz" class="x.y.Baz"/>
</beans>
Spring会检查bean之间的依赖关系,会先加载(初始化)被依赖的bean,在例子中,bar和baz首先被加载,然后通过构造函数参数的形式注入到foo中。相信这个很好理解吧。
除了支持bean的注入之外,Spring还支持常量的注入,如下:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
其中constructor-arg需要根据构造函数的顺序对应好(参数类型要匹配)。
除了默认的顺序排序,我们还可以指定Index属性,来指定constructor-arg对应构造函数参数的位置:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
另外还可以指定参数名称来对应指定构造函数参数,但是这种方式需要给类的构造函数加上 @ConstructorProperties注解:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateanswer" value="42"/>
</bean>
package examples;
public class ExampleBean {
// Fields omitted
@ConstructorProperties({"years", "ultimateAnswer"})
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
2.2 Setter方式
实现方式如下:
java代码:
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public void setBeanOne(AnotherBean beanOne) {
this.beanOne = beanOne;
}
public void setBeanTwo(YetAnotherBean beanTwo) {
this.beanTwo = beanTwo;
}
public void setIntegerProperty(int i) {
this.i = i;
}
}
bean配置:
<bean id="exampleBean" class="examples.ExampleBean">
<!-- setter injection using the nested <ref/> element -->
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property>
<!-- setter injection using the neater 'ref' attribute -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
Spring在实例化bean之后,会将配置中property属性通过对应的setter方法将被引用对象设置到bean的属性中。同样的,被引用的bean会先于引用bean被Spring加载实例化。
属性的setter方法需要遵循java的标准,即set + 属性名(首字母改为大写)。
在上面例子中
<property name="beanTwo" ref="yetAnotherBean"/>
还可以写成:
<property name="beanTwo"/>
<idref bean="yetAnotherBean"/>
</property>
或者:
<property name="beanTwo" value="yetAnotherBean"/>
通过<idref/>标签,Spring会去查找容器中ID为指定值的bean。
3 其他依赖注入功能
3.1 <ref/>标签引用不同范围的bean
之前我们所看到的例子都是bean引用了同一个Spring容器中的bean,Spring还支持bean引用同个XML配置文件中的bean,或者是父容器的bean。写法分别是:
引用当前容器中的bean:
<ref bean="someBean"/>
引用父容器中的bean:
<ref parent="someBean"/>
引用当前XML中的bean:
<ref local="someBean"/>
3.2 内部bean
内部bean指的是在某个bean内部配置的bean。配置方式如下:
<bean id="outer" class="...">
<!-- instead of using a reference to a target bean, simply define the target bean inline -->
<property name="target">
<bean class="com.example.Person"> <!-- this is the inner bean -->
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</bean>
内部bean可以不用的id和name属性。
3.3 集合注入
除了注入基础类型和bean之外,我们还可以对bean中的集合属性进行注入,List,Set,Map,Properties分别对应配置中的<list/>,<set/>,<map/>,<props/>标签,配置方式如下:
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string" />
<entry key="a ref" value-ref="myDataSource" />
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>
3.4 集合合并
假设我们有一个bean collectionParent,collectionParent里有个Properties类型的属性config:
<bean id="collectionParent" class="cn.com.willchen.test.di.CollectionMergeInject">
<property name="config">
<props>
<prop key="url">localhost</prop>
<prop key="port">8080</prop>
</props>
</property>
</bean>
这时,因为业务需要,我们可能有多种场景,需要用到不同的config,或者内容更多的config,假设port属性改了,而且需要多一个protocol属性,那么我们可以这么做:
<bean id="collectionChild" parent="collectionParent">
<property name="config">
<!-- the merge is specified on the *child* collection definition -->
<props merge="true">
<prop key="protocol">http</prop>
<prop key="port">9090</prop>
</props>
</property>
</bean>
collectionChild的配置通过parent属性继承collectionParent,再在config的props标签中加入merge="true"的属性,就可以实现将collectionParent中config的配置合并过来。
实例化后collectionParent的config属性是{port=8080, url=localhost}
collectionChild的config属性是{port=9090, url=localhost, protocol=http}
注意,重复的元素会被覆盖。
这里用的是Properties作为例子,同样的List,Map,Set也可以,但是对于List略有不同,List是以链表形式出现的,是有序的,2个List合并成1个List后,parent List的元素肯定在child List元素之前。
不同类型的集合之间不能合并,否则Spring会抛出异常。
3.5 强类型集合注入
假设我们的bean 类中属性定义的是一个强类型的集合如Map<Sring, Fload>,Spring同样支持注入:
public class Foo {
private Map<String, Float> accounts;
public void setAccounts(Map<String, Float> accounts) {
this.accounts = accounts;
}
}
<bean id="foo" class="x.y.Foo">
<property name="accounts">
<map>
<entry key="one" value="9.99" />
<entry key="two" value="2.75" />
<entry key="six" value="3.99" />
</map>
</property>
</bean>
例中的9.99,2.75,3.99在注入属性前Spring会自动做类型转换,例子中转为Float类型。
3.6 null和空字符串
这个比较简单,没什么好说的,看例子:
空字符串:
<bean class="ExampleBean">
<property name="email" value=""/>
</bean>
null:
<bean class="ExampleBean">
<property name="email"><null/></property>
</bean>
3.7 p-namespace方式配置属性注入
p-namespace方式是用于替换<property/>标签的另外一种简洁的写法,通常我们给一个bean注入属性是这么写的:
<bean name="classic" class="com.example.ExampleBean">
<property name="email" value="foo@bar.com"/>
</bean>
在Spring 2.0之后,我们可以这么写:
<bean name="p-namespace" class="com.example.ExampleBean" p:email="foo@bar.com"/>
</beans>
如果我们的bean的属性引用了其他bean,我们可以这么写:
<bean name="john-modern" class="com.example.Person" p:name="John Doe" p:spouse-ref="jane"/> <bean name="jane" class="com.example.Person">
<property name="name" value="Jane Doe"/>
</bean>
p:spouse-ref中spouse是属性的名称,-ref表示引用了其他bean。
但是在实际项目中,我们还是需要保证所有配置使用一种风格,要么<property/>要么p-namespace格式。
3.8 c-namespace方式配置构造函数参数注入
c-namespace方式是用于替换<constructor-arg/>标签的另外一种写法,通常定义一个bean的构造函数的参数是这么写的:
<bean id="bar" class="x.y.Bar"/>
<bean id="baz" class="x.y.Baz"/> <bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
<constructor-arg value="foo@bar.com"/>
</bean>
通过c-namespace我们可以这么写:
<bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="foo@bar.com">
写法和p-namespace类似,也就把p换成c而已。
3.9 嵌套属性注入
假设bean中有个属性A,属性A里有个属性B,那么我们也可以通过配置给A.B赋值:
<bean id="foo" class="foo.Bar">
<property name="fred.bob.sammy" value="123" />
</bean>
需要注意的是,父属性不能为空,如例子中 fred不能为null,fred.bob也不能为null,否则在注入的时候会抛出空指针异常。
Srping - bean的依赖注入(Dependency injection)的更多相关文章
- 简明依赖注入(Dependency Injection)
前言 这是因特奈特上面不知道第几万篇讲依赖注入(Dependency Injection)的文章,但是说明白的却寥寥无几,这篇文章尝试控制字数同时不做大多数. 首先,依赖注入的是一件很简单的事情. 为 ...
- 控制反转Inversion of Control (IoC) 与 依赖注入Dependency Injection (DI)
控制反转和依赖注入 控制反转和依赖注入是两个密不可分的方法用来分离你应用程序中的依赖性.控制反转Inversion of Control (IoC) 意味着一个对象不会新创建一个对象并依赖着它来完成工 ...
- 14.AutoMapper 之依赖注入(Dependency Injection)
https://www.jianshu.com/p/f66447282780 依赖注入(Dependency Injection) AutoMapper支持使用静态服务定位构建自定义值解析器和自定 ...
- Spring点滴七:Spring中依赖注入(Dependency Injection:DI)
Spring机制中主要有两种依赖注入:Constructor-based Dependency Injection(基于构造方法依赖注入) 和 Setter-based Dependency Inje ...
- 依赖注入 | Dependency Injection
原文链接: Angular Dependency Injection翻译人员: 铁锚翻译时间: 2014年02月10日说明: 译者认为,本文中所有名词性的"依赖" 都可以理解为 & ...
- Spring之对象依赖关系(依赖注入Dependency Injection)
承接上篇: Spring中,如何给对象的属性赋值: 1:通过构造函数,如下所示: <!-- 1:构造函数赋初始值 --><bean id="user1" clas ...
- 设计模式之————依赖注入(Dependency Injection)与控制反转(Inversion of Controller)
参考链接: 依赖注入(DI) or 控制反转(IoC) laravel 学习笔记 —— 神奇的服务容器 PHP 依赖注入,从此不再考虑加载顺序 名词解释 IoC(Inversion of Contro ...
- 理解依赖注入(Dependency Injection)
理解依赖注入 Yii2.0 使用了依赖注入的思想.正是使用这种模式,使得Yii2异常灵活和强大.千万不要以为这是很玄乎的东西,看完下面的两个例子就懂了. class SessionStorage { ...
- AngularJS - 依赖注入(Dependency Injection)
点击查看AngularJS系列目录 转载请注明出处:http://www.cnblogs.com/leosx/ 依赖注入 依赖注入是软件设计模式中的一部分,用于处理组件是如何得到它说依赖的其它组件的. ...
随机推荐
- github+hexo搭建自己的博客网站(二)更换主题yilia
开始更换主题,hexo默认的主题是landscape,可以更换为其他的主题yilia主题 详细的可以查看hexo博客的演示:saucxs.github.io 可以查看在github上生成的静态文件:h ...
- SQL实现 模糊查询(转)
在进行数据库查询时,有完整查询和模糊查询之分. 一般模糊查询语句如下: SELECT 字段 FROM 表 WHERE 某字段 Like 条件 其中关于条件,SQL提供了四种匹配模式: 1,% :表示任 ...
- IT类非开发面试总结--1
面试总结.. ================================= 第一部分.. -------------2. 电脑开机时风扇转, 但是屏幕没有任何显示, 此现象可能是哪些方面所导致? ...
- archlinux系统安装博通B43XX系列无线网卡驱动
我的无线网卡是博通的B43xx系列,大家都知道博通对于其Wifi卡在 GNU/Linux 上的支持不好可谓是臭名昭著. 用 lspci -vnn -d 14e4: 或者 lspci -vnn | gr ...
- 【渗透课程】第五篇-SQL注入的原理
哈哈哈,讲到注入了.我想给大家讲注入的原理.这个我们前面的前言篇就说过,所谓的SQL注入就是,绕过数据库验证机制直接执行SQL语句.怎么说呢,我们先讲一个概念吧! 网站和网页的区别 单纯的网页是静态的 ...
- [2016-07-15]nuget包管理器控制台下的powershell脚本介绍
博客有阵子没打理了,今天刚恢复样式,但是标题还是不太正常,总算能凑合看看. 回到正题,最近为了能在VS的程序包管理器控制台上能方便的自定义ps脚本去调整project的package,就开始看powe ...
- css控制竖直文字显示
假如有一天,你把水平文字看腻味了...... 我建议你不妨试试垂直文字显示,就像这样: 我 是 竖 直 显 示 的 : 哈哈! 言归正传,怎么把一段话,垂直显示呢? 方法1: //把下面代码另存为ht ...
- jQuery选中下拉列表,输出值
jQuery部分: $("#form1 select").change(function () { var s=[]; $("#form1 select :selecte ...
- base64随机字符混淆加密、解密-美拍视频地址解密,反推加密算法
用火车头测试采集美拍的数据时无意中发现美拍的视频地址是一段加了混淆字符串的base64代码.如下图 于是好奇之下研究了下解密算法.具体过程省略800字.发现美拍的视频解密是通过js完成,于是找到了具体 ...
- Microsoft Visual Studio 打开代码出现乱码解决方案
在用VS编写代码时,文本的字符集可能和编译器的字符集不同,在这种情况下代码会显示出乱码. 解决办法: 在VS的工具->选项里面找到"文本编辑器",勾选“自动检测不带签名的UT ...