依赖注入 有三种方式,本文只学习下属性注入.

属性注入

      属性注入即通过 setXxx方法()注入Bean的属性值或依赖对象,由于属性注入方式具有可选择性和灵活性高的优点,因此属性注入方式是实际应用中最常用的注入方式。

属性注入的实例

属性注入要求Bean提供一个默认的构造函数,并为需要注入的属性提供对应的Setter方法。Spring先调用Bean的默认构造函数实例化Bean对象,然后通过反射的方式调用Setter方法注入属性值。先看一个简单的例子
package com.spring.model;

public class Car {
/**
* 系统为自动我们提供一个无参的构造方法
*/
private String brand;
private String color;
private int maxSpeed;
public void setBrand(String brand) {
this.brand = brand;
}
public void setColor(String color) {
this.color = color;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
}

Car 类中定义了3个属性,并提供了对应的Setter方法.
小提示:默认构造函数是不带参数的构造函数。Java语言规定,如果类中没有定义任何构造函数,则JVM自动为其生成一个默认的构造函数。反之,如果类中显示定义了构造函数,则JVM不会为其生成默认的构造函数。所以假设Car类中定义了一个带参的构造函数,如public Car(String brand),则需要同时提供一个默认构造函数public Car(),否则使用属性注入时将抛出异常。
下面是在Spring配置文件中,对Car进行属性注入时的配置片段.
  <bean  id="car" class="com.spring.model.Car" >
<property name="maxSpeed"><value>200</value></property>
<property name="brand"><value>红旗CAT2</value> </property>
<property name="color"><value>红色</value></property>
</bean>

我们配置了一个Car Bean,并为该Bean的三个属性提供了属性值。具体来说,Bean的每一个属性对应一个<property>标签,name为属性的名称,在Bean实现类中拥有与其对应的Setter方法:maxSpeed对应setMaxSpeed。


注入参数详解

字面值

上面使用的方式就是字面值。

引用其它Bean

Spring IOC容器中定义的bean可以相互引用,IOC容器则充当红娘的角色。下面我们创建一个新的Boss类,Boss类中拥有一个Car类型的属性:
package com.spring.model;

public class Boss {
private Car car=new Car(); public Car getCar() {
return car;
}
//设置Car属性
public void setCar(Car car) {
this.car = car;
}
..........
}
boss 的Bean通过<ref>元素引用car Bean,建立起Boss对car的依赖。
   <!-- 1 car bean -->
<bean id="car" class="com.spring.model.Car" />
<bean id="boss" class="com.spring.model.Boss">
<property name="car">
<!--2 引用1处定义的car bean -->
<ref bean="car"/>
</property>
</bean>

<ref>元素可以通过以下三个属性引用容器中的其它Bean。

(1)bean:通过该属性可以引用同一容器或父容器的Bean,这是最常见的形式。
(2)local:通过该属性只能引用同一配置文件中定义的Bean,它可以利用XML解析器自动校验引用的合法性,以便在开发编写配置时能够及时发现并纠正错误;
(3)parent:引用父容器中的Bean,如<ref parent="car">的配置说明car的Bean是父容器的Bean。

为了说明子容器对父容器Bean的引用,来看一个具体的例子。假设有两个配置文件:beans1.xml 和beans2.xml,其中beans.xml被父容器加载,其配置内容如下:
beans1.xml
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!--1 在父容器定义的bean -->
<bean id="car" class="com.spring.model.Car">
<property name="brand">
<value>红旗</value>
</property>
<property name="color" value="红色"/>
<property name="maxSpeed" value="200"/>
</bean>
</beans>

beans2.xml

<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!--该bean和父容器的car bean具有相同的id-->
<bean id="car" class="com.spring.model.Car">
<property name="brand">
<value>白旗CAR</value>
</property>
<property name="color" value="红色"/>
<property name="maxSpeed" value="200"/>
</bean> <bean id="boss" class="com.spring.model.Boss">
<property name="car">
<!-- 引用父容器的car,而非beans2.xml定义的car ,如果采用<ref bean="car" 则会引用本容器的car/> -->
<ref parent="car"/>
</property>
</bean>
</beans>

在beans1.xml中定义了一个car bean,在beans2.xml也定义了一个car Bean。分别通过父子容器加载beans1.xml和beans2.xml,beans2.xml中的boss通过<ref parent="car">将引用到父容器中的car.

下面是分别和父子容器加载beans1.xml和beans2.xml配置文件的代码:
	@Test
public void test1(){
//父容器
ApplicationContext pFactory=new ClassPathXmlApplicationContext("beans1.xml");
//指定pFactory为该容器的父容器
ApplicationContext factory=new ClassPathXmlApplicationContext(new String[]{"beans2.xml"},pFactory); Boss boss=(Boss) factory.getBean("boss");
System.out.println(boss.getCar().getBrand()); }

运行后结果如下:

红旗

内部Bean

   如果car bean只被Boss bean引用,而不会被容器中任何其它的bean引用,则可以将car以内部bean的方式注入到Boss中。
      <bean id="boss" class="com.spring.model.Boss">
<property name="car">
<bean class="com.spring.model.Car">
<property name="maxSpeed" value="200"/>
<property name="color" value="白色"/>
</bean>
</property>
</bean>

内部bean和JAVA代码中匿名内部类很相似,即没有名字,也不能被其它bean引用,只能在声明处为外部bean提供实例注入。 内部bean即使提供了id、name、scope属性,也会被忽略,scope默认为prototype类型.


null值

     <property name="barnd">
<value><null/> </value>
</property>

级联属性

和Struts、Hibernate等框架一样,Spring支持级联属性的配置。假设我们在定义Boss时直接为Car的属性提供注入值,则可以采取以下的配置方式:
   <bean id="boss2" class="com.spring.model.Boss">
<!-- 以原点的方式定义级别属性 -->
<property name="car.brand" value="吉利Ct50"/>
</bean>

按照上面的配置,Spring将调用Boss.getCar.setBaran("吉利Ct50"),方法进行属性的注入操作。

Spring 没有对级联属性的层级数进行限制,只要配置的Bean拥有对应于级联属性的类结构,就可以配置任意层级的级联属性,如<property name="car.wheel.brand" value="双星" />定义了具有三级结构的级联属性。

集合类型属性

java.util包中的集合类是最常用的数据结构类型,主要包括List、Set、Map、Properties,Spring为这些集合类型属性配置了专门的配置元素标签。
   List
我们为Boss类添加一个List类型的favourites属性:
package com.spring.model;

import java.util.ArrayList;
import java.util.List; public class Boss { private List favourites=new ArrayList(); public List getFavourites() {
return favourites;
}
public void setFavourites(List favourites) {
this.favourites = favourites;
}}

对应Spring 中的配置片段如下所示:

      <bean id="boss" class="com.spring.model.Boss">
     <property name="favourites">
<list>
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</list>
</property>
</bean>

List属性既可以通过<value>注入字符串,也可以通过<ref>注入容器中其它的Bean.

Set
如果Boss的favourites属性时java.util.set.,则采用如下的配置方式:
      <bean id="boss" class="com.spring.model.Boss">
     <property name="favourites">
<set>
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</set>
</property>
</bean>

Map

下面我们为Boss添加一个Map类型的jobs属性:
package com.spring.model;

import java.util.HashMap;
import java.util.Map; public class Boss {
private Map jobs=new HashMap(); public Map getJobs() {
return jobs;
} public void setJobs(Map jobs) {
this.jobs = jobs;
} }

在配置文件中,可以通过如下方式为jobs属性提供配置值:

      <bean id="boss" class="com.spring.model.Boss">
<property name="jobs">
<map>
<!-- Map 第一个元素 -->
<entry>
<key><value>AM</value></key>
<value>会见客户</value>
</entry>
<!-- Map第二个元素 -->
<entry>
<key><value>PM</value></key>
<value>公司内部会议</value>
</entry>
</map>
</property>
</bean>

假设某一Map元素的键和值都是对象,则可以采取以下的配置方式:

                  <entry>
<key><ref bean="keyBean"/> </key>
<ref bean="valueBean"/>
</entry>

Properties

Properties类型其实可以看成是Map类型的特例。Map元素的键和值可以为任何类型的对象,而Properties属性的键和值都只能是字符串,我们为Boss添加一个Properties类型的mail属性:
package com.spring.model;

import java.util.Properties;

public class Boss {
private Properties mails=new Properties(); public Properties getMails() {
return mails;
} public void setMails(Properties mails) {
this.mails = mails;
} }

下面的配置片段为mails提供了配置:

      <bean id="boss" class="com.spring.model.Boss">
<property name="mails">
<props>
<prop key="jobMail">john-office@taobao.com</prop>
<prop key="lifeMail">john-life@taobao.com</prop>
</props>
</property>
</bean>

因为Properties键值对只能是字符串,因此其配置比Map的配置要简单一些,注意值的配置没有<value>子元素标签.

强类型集合

下面Boss类的jobTime属性采用强类型的Map类型:元素的键为String类型;而值为Integer类型。
package com.spring.model;

import java.util.HashMap;
import java.util.Map; public class Boss {
private Map<String,Integer> jobTime =new HashMap<String, Integer>(); public Map<String, Integer> getJobTime() {
return jobTime;
} public void setJobTime(Map<String, Integer> jobTime) {
this.jobTime = jobTime;
}
}

在Spring中的配置和非强类型集合相同:

    <bean id="boss" class="com.spring.model.Boss">
<property name="jobTime">
<map>
<entry>
<key> <value>会见客户</value></key>
<value>124</value>
</entry>
</map>
</property>
</bean>

但Spring 容器在注入强类型集合时,会判断元素的类型,将设置值转换为对应的数据类型。如上面代码中的设置项124将被转换为Integer类型.

集合合并

Spring2.0新增了集合合并的功能,允许子<bean>继承父<bean>中配置的同名属性值合并起来作为最终bean的属性值。
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- 父bean -->
<bean id="parentBoss" abstract="true" class="com.spring.model.Boss">
<property name="favorites">
<set>
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</set>
</property>
</bean> <!-- 子bean -->
<bean id="childBoss" class="com.spring.model.Boss" parent="parentBoss">
<property name="favorites">
<set merge="true">
<value>爬山</value>
<value>游泳</value>
</set>
</property>
</bean>
</beans>

在代码清单中,通过merge="true"属性指定子<bean>和父<bean>中的同名属性值进行合并,即子<bean>的favourites元素将最终拥有5个元素。如果设置merge="false",则不会和父<bean>同名集合属性进行合并,即子Bean的favourites属性集合只有两个元素.

	@Test
public void test2(){
ApplicationContext ctx=new ClassPathXmlApplicationContext("beans2.xml");
Boss boss=(Boss) ctx.getBean("childBoss");
Set set=boss.getFavorites();
System.out.println(set);
}

运行后结果如下:

[看报, 赛车, 高尔夫, 爬山, 游泳]






Spring 学习笔记 ----依赖注入的更多相关文章

  1. Spring学习笔记--依赖注入

    依赖注入和控制反转:http://baitai.iteye.com/blog/792980出自李刚<轻量级 Java EE 企业应用实战> Java应用是一种典型的依赖型应用,它就是由一些 ...

  2. Spring 学习之依赖注入

    什么是依赖关系? 纵观所有的Java 应用,从基于Applet的小应用到多层次结构的企业级别的应用,他们都是一种典型的依赖性应用,也就是由一些互相协作的对象构成的,Spring把这种互相协作的关系称之 ...

  3. Spring学习(一)---依赖注入和控制反转

    Spring Spring是一个从实际开发中抽出来的框架,因此它完成了大量开发中的通用步骤,留给开发者的仅仅是与特定应用相关的部分,从而大大提高了企业应用的开发效率. Spring为企业应用的开发提供 ...

  4. spring学习之依赖注入DI与控制反转IOC

    一 Ioc基础 1.什么是Ioc? Ioc(Inversion of Control)既控制反转,Ioc不是一种技术,而是一种思想,在Java开发中意味着将设计好的对象交给容器来进行控制,并不是像传统 ...

  5. net5学习笔记---依赖注入

    小王的故事 小王去上班 ​ 小王是个程序员,每个工作日他都要去上班,诸多交通工具他最喜欢的交通工具是骑电车.在骑行的过程中放空自己使他很快. ​ 突然有一天天气预报说近期有很大的雨,小王再想骑电车去上 ...

  6. spring学习 五 依赖注入的方式

    依赖注入有两种方式: 1 构造注入,如果<bean>标签下使用<contructor-arg>,则是构造注入 2 setter注入,就是调用setter方法注入,如果<b ...

  7. Spring学习——DI(依赖注入)

    IOC容器,处理对象依赖关系 IOC与DI: IOC :是一个容器,创建对象的容器 DI :在容器创建对象后,处理对象的依赖关系,也叫依赖注入! 方式1:通过set方法注入值 可以给普通属性.集合属性 ...

  8. Spring学习笔记--构造器注入

    之前讲到的名为"duke"的bean有一个私有成员变量beanBags代表这个杂技师bean的一次性能够抛出的最多的数量,Juggler有一个构造函数,构造函数的第一个参数(这里只 ...

  9. Spring学习--泛型依赖注入

    暂时没有搞懂.

随机推荐

  1. java中&和&&的区别 位运算

    1.1. 逻辑与的运算符功能 1.1.1. 测试&& public static void main(String[] args) { int x=5; if (x==6 && ...

  2. 【Unity Shaders】ShadowGun系列之一——飞机坠毁的浓烟效果

    写在前面 最近一直在思考下面的学习该怎么进行,当然自己有在一边做项目一边学OpenGL,偶尔翻翻论文之类的.但是,写shader是一个需要实战和动手经验的过程,而模仿是前期学习的必经之路.很多人都会问 ...

  3. 物料事务处理interface与temp解析

    MTL_TRANSACTIONS_INTERFACE MTL_TRANSACTIONS_INTERFACE is the interface point between non– Inventory ...

  4. [Mac] mac linux 多线程下载利器 axel

    ​> 之前做过一些文件下载的统计,发现谷歌浏览器chrome和火狐firefox, 一般都是单线程的下载文件,360浏览器却是多线程的下载. 现在切换到了mac上,发现没有360哪个浏览器,就像 ...

  5. findViewById中NullPointerException的错误

    最近在弄一个对话框的登录时,发现一个总是报NullPointerException的错误,折腾了两小时,一直没有发现细小的区别..先上图,一边说明原因 首先是 Activity类中定义的findVie ...

  6. Android开发技巧——实现底部图标文字的导航栏(已更新)

    本文章的导航栏代码参考了viewpagerindicator的实现.本文叙述的是之前版本的qq或微信中,底部的图标加文字的导航栏的实现. 2014-09-14 13:59:42更新:library的代 ...

  7. 使用HTML5拍照

    原文连接地址: Camera and Video Control with HTML5 演示地址: HTML5拍照演示 翻译日期: 2013年8月6日 首先,我们看看HTML代码结构,当然,这部分的D ...

  8. 【翻译】在Ext JS 6通用应用程序中使用既共享又特定于视图的代码

    原文:Using Both Shared and View-Specific Code in an Ext JS 6 Universal App 在本文,在展示如何编写Ext JS 6通用应用程序代码 ...

  9. List常用整理

            长期更新,主要记录List的各种常用操作整理. 对List进行排序 // Collections.sort(重写toString()进行排序区分) List<ObjectName ...

  10. 03_Android项目中读写文本文件的代码

    编写一下Android界面的项目 使用默认的Android清单文件 <?xml version="1.0" encoding="utf-8"?> & ...