Spring中Bean的配置

IOC&DI概述

配置Bean

  • 配置形式:基于XML文件的方式;基于注解的方式
  • Bean的配置方式:通过全类名(反射)、通过工厂方法(静态工厂方法&实例工厂方法)、FactoryBean
  • IOC容器BeanFactory&ApplicationContext概述
  • 依赖注入的方式:属性注入;构造器注入
  • 注入属性值的细节
  • 自动装配
  • bean之间的关系:继承;依赖
  • bean的作用域:singleton;prototype;WEB环境作用域
  • 使用外部属性文件
  • spEL
  • IOC容器中的Bean的生命周期
  • Spring4.x新特性:泛型依赖注入

IOC和DI

IOC(Inversion of Control):其思想是反转资源获取的方向。传统的资源查找方式要求组件向容器发起请求查找资源。作为回应,容器适时的返回资源。而应用了IOC之后,则是容器主动地将资源送给它所管理的组件,组件要做的仅仅是选择一种合适的方式来介绍资源。这种行为也被称为查找的被动形式
DI(Dependency Injection)–IOC的另一种表述方式:即组件以一些预先定义好的方式(例如:setter方法)接受来自如容器的资源注入。相对于IOC而言,这种表述更直接

IOC&DI原理

IOC前生 — 分离接口与实现

  • 需求:生成HTML或PDF格式的不同类型的报表

IOC前生 — 采用工厂设计模式

IOC — 采用反转控制

Bean的配置方式

在Spring的IOC容器里配置Bean

  • 在XML文件中通过bean节点来配置bean

    1
    2
    3
    4
    <!-- 通过全类名的方式来配置bean -->
    <bean id = "helloWorld"
    class = "com.spring.helloworld.HelloWorld">
    </bean>
  • id:Bean的名称

  1. 在IOC容器中必须是唯一
  2. 若id没有指定,Spring自动将权限定性类名作为Bean的名字
  3. id可以指定多个名字,名字之间可用逗号、分号、或者空格分隔

Spring容器

  • SpringIOC容器容器读取Bean配置创建Bean实例之前,必须对它进行实例化。只有在容器实例化后,才可以从IOC容器里获取Bean实例并使用。
  • Spring提供了两种类型的IOC容器实现。
  1. BeanFactory:IOC容器的基本实现。
  2. ApplicationContext:提供了更多的高级特性。是BeanFactory的子接口。
  3. BeanFactory是Spring框架的基础设施,面向Spring本身;ApplicationContext面向使用Spring框架的开发者,几乎所有的应用场合都直接使用ApplicationContext而非底层的BeanFactory
  4. 无论使用何种方式,配置文件时相同的。

ApplicationContext

  • ApplicationContext的主要实现类:
  1. ClassPathXmlApplicationContext:从类路径下加载配置文件
  2. FileSystemXmlApplicationContext:从文件系统中加载配置文件
  • ConfigurableApplicationContext扩展与ApplicationContext,新增两个主要方法:refresh()和close(),让ApplicationContext具有启动、刷新和关闭上下文的能力
  • ApplicationContext在初始化上下文时就实例化所有单例的Bean
  • WebApplicationContext是专门为WEB应用而准备的,它允许从相对于WEB根目录的路径中完成初始化工作

从IOC容器中获取Bean

  • BeanFactory
    • FACTORY_BEAN_PREFIX:String
    • getBean(String):Object
    • getBean(String,Class<T>)<T>:T
    • getBean(Class<T>)<T>:T
    • getBean(String,Object…):Object
    • containsBean(String):boolean
    • isSingleton(String):boolean
    • isPrototype(String):boolean
    • isTypeMatch(String,Class<?>):boolean
    • getType(String):Class<?>
    • getAliases(String):String[]
  • 具体实例
    1
    2
    3
    4
    5
    6
    7
    8
    //1.创建Spring 的IOC容器对象
    //ApplicationContext 代表IOC容器
    //ClassPathXmlApplicationContext:是ApplicationContext 接口的实现类
    ApplicationContext act = new ClassPathXmlApplicationContext("spring-config.xml");
    //2.从IOC容器中获取Bean实例
    HelloWorld helloWorld = (HelloWorld)act.getBean("helloWorld");
    //3.调用hello方法
    helloWorld.hello();

属性注入

  • 属性注入即通过setter方法注入Bean的属性值或依赖的对象
  • 属性注入使用<property>元素,使用name属性指定Bean的属性名称,value属性或<value>子节点指定属性值
  • 属性注入是实际应用中最常见的注入方式
1
2
3
4
5
6
<!-- 通过全类名的方式来配置bean -->
<bean id = "helloWorld"
class = "com.spring.helloworld.HelloWorld">
<property name="name" value="HuiProgramer"></property>
<property name="age" value="22"></property>
</bean>

构造方法注入

  • 通过构造方法注入Bean的属性值或者依赖的对象,它保证了Bean实例在实例化后就可以使用
  • 构造器注入在<constructor-arg>元素里声明属性,<constructor-arg>中没有name属性

按顺序配置

1
2
3
4
5
6
<!-- 通过构造方法来配置bean属性 -->
<bean id = "car" class = "com.spring.helloworld.Car">
<constructor-arg value = "Audi"></constructor-arg>
<constructor-arg value = "ShangHai"></constructor-arg>
<constructor-arg value = "30000"></constructor-arg>
</bean>

按index配置

1
2
3
4
5
6
<!-- 通过构造器注入属性值可以指定参数的位置 -->
<bean id = "car" class = "com.spring.helloworld.Car">
<constructor-arg value = "Audi" index = "0"></constructor-arg>
<constructor-arg value = "30000" index = "2"></constructor-arg>
<constructor-arg value = "ShangHai" index = "1"></constructor-arg>
</bean>

按type配置

1
2
3
4
5
6
<!-- 通过构造器注入属性值可以指定参数的类型 -->
<bean id = "car" class = "com.spring.helloworld.Car">
<constructor-arg value = "Audi" type = "java.lang.String"></constructor-arg>
<constructor-arg value = "30000" type = "long"></constructor-arg>
<constructor-arg value = "ShangHai" type = "java.lang.String"></constructor-arg>
</bean>

提示: 通过构造器注入参数的类型和位置可以混合使用

字面值

  • 字面值:可用字符串表示的值,可以通过<value>元素标签或value属性进行注入
  • 基本数据类型及其封装类,String等类型都可以采用字面值注入的方式
  • 若字面值中包含特殊字符,可用使用<![CDATA[]]>把字面值包裹起来

实例:

1
2
3
4
5
6
7
8
9
<!-- 通过构造器注入属性值可以指定参数的位置和类型 -->
<bean id = "car2" class = "com.spring.helloworld.Car">
<constructor-arg value = "Audi" index = "0"></constructor-arg>
<constructor-arg value = "30000" index = "2"></constructor-arg>
<!-- 如果字面值包含特殊字符可以用<![CDATA[ ]]>包裹起来 -->
<constructor-arg type = "java.lang.String">
<value><![CDATA[<ShangHai>]]></value>
</constructor-arg>
</bean>

输出结果:
<ShangHai>

引用其它Bean

  • 组成应用程序的Bean经常需要相互协作以完成应用程序的功能,要使Bean能够相互访问,就必须在Bean配置文件中指定对Bean的引用
  • 在Bean的配置文件中,可用通过<ref>元素或ref属性为Bean的属性或构造器参数指定对Bean的引用
  • 也可以在属性或构造器里包含Bean的声明,这样的Bean称为内部Bean

外部Bean实例:

1
2
3
4
5
<!-- 通过方法注入属性值 -->
<bean id = "person" calss = "com.spring.hellowrld.person">
<property name="name" value="HuiProgramer"></property>
<property name="Car" ref = "car"></property>
</bean>

内部Bean实例:

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 通过方法注入属性值 -->
<bean id = "person" calss = "com.spring.hellowrld.person">
<property name="name" value="HuiProgramer"></property>
<property name="Car">
<!-- 通过构造器注入属性值可以指定参数的类型 -->
<bean id = "car" class = "com.spring.helloworld.Car">
<constructor-arg value = "Audi" type = "java.lang.String"></constructor-arg>
<constructor-arg value = "30000" type = "long"></constructor-arg>
<constructor-arg value = "ShangHai" type = "java.lang.String"></constructor-arg>
</bean>
</property>
</bean>

null值和级联属性

  • 可以使用专用的<null/>元素标签为Bean的字符串或其它对象类型的属性注入null值
  • 和Struts、Hiberante等框架一样,Spring支持级联属性的配置

null值注入实例:

1
2
3
4
5
6
7
<!-- 通过构造方法来配置bean属性 -->
<bean id = "car3" class = "com.spring.helloworld.Car">
<constructor-arg value = "Audi"></constructor-arg>
<!-- 注入null值 -->
<constructor-arg ><value><null/></value></constructor-arg>
<constructor-arg ><value><null/></value></constructor-arg>
</bean>

级联属性的配置:

1
2
3
4
5
6
7
<!-- 通过方法注入属性值 -->
<bean id = "person" calss = "com.spring.hellowrld.person">
<property name="name" value="HuiProgramer"></property>
<property name="Car" ref = "car"></property>
<!-- 给级联属性赋值,注意:属性需要先初始化后才可以给级联属性赋值,否则会发生异常,和Struts2不同 -->
<property name="Car.corp" value = "50000"></property>
</bean>

集合属性

  • 在Spring中可以通过一组内置的XML标签(例如:<list>,<set>或<map>)来配置集合属性
  • 配置java.util.List类型的属性,需要指定<list>标签,在标签里包含一些元素,这些标签可以通过<value>指定简单的常量值,通过<ref>指定对其他Bean的引用,通过<bean>指定内置Bean定义。通过<null/>指定空元素,设置可以内嵌其他集合
  • 数组的定义和List一样,都使用<list>
  • 配置java.util.Set需要使用<set>标签,定义元素的方法与List一样。
  • Java.util.Map通过<map>标签定义,<map>标签里可以使用多个<entry>作为子标签,每个条目包含一个键和一个值。
  • 必须在<key>标签里定义键
  • 因为键和值的类型没有限制,所以可以自由地为他们指定<value>,<ref>,<bean>或<null>元素。
  • 可以将Map的键和值作为<entry>的属性定义:简单常量使用key和value来定义;Bean引用通过key-ref和value-ref属性定义
  • 使用<props>定义java.util.Properties,该标签使用多个<prop>作为子标签,每个<prop>标签必须定义key属性.

List实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- 通过方法注入属性值 -->
<bean id = "person" calss = "com.spring.hellowrld.person">
<property name="name" value="HuiProgramer"></property>
<property name="Cars" >
<!-- 使用list节点为List类型的属性赋值 -->
<list>
<ref bean = "car2" />
<ref bean = "car3" />
<!-- 通过Bean直接指定 -->
<bean id = "car" class = "com.spring.helloworld.Car">
<constructor-arg value = "Audi" type = "java.lang.String"></constructor-arg>
<constructor-arg value = "30000" type = "long"></constructor-arg>
<constructor-arg value = "ShangHai" type = "java.lang.String"></constructor-arg>
</bean>
</list>
</property>

</bean>

Map实例:

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 配置Map属性值 -->
<bean id = "Person" calss = "com.spring.hellowrld.person">
<property name = "name" value = "Rose"></property>
<property name = "age" value = "28"></property>
<property name = "Cars">
<!-- 使用 map 节点及map的entry子节点配置 Map -->
<map>
<entry key = "AA" value-ref = "car3"></entry>
<entry key = "BB" value-ref = "car2"></entry>
</map>
</property>
</bean>

Properties实例:

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 配置Properties 属性值 -->
<bean id = "dataSource" calss = "com.spring.hellowrld.dataSource">
<property name = "properties">
<!-- 使用 props 和 prop 子节点来为 Properties 属性赋值 -->
<props>
<prop key = "user">root</prop>
<prop key = "password">1234</prop>
<prop key = "jdbcUrl">jdbc:mysql:///test</prop>
<prop key = "driverClass">com.mysql.jdbc.Driver</prop>
</props>
</property>
</bean>

使用utility scheme定义集合

  • 使用基本的集合标签定义集合时,不能将集合作为独立的Bean定义,导致其他Bean无法引用该集合,所以无法在不同Bean之间共享集合
  • 可以使用util schema里的集合标签定义独立的集合Bean,需要注意的事,必须在<beans>根元素里添加退了 schema 定义。

配置单例集合Bean:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 配置单例的集合Bean,以供多个bean进行引用,需要导入util命名空间 -->
<util:list id = "cars">
<ref bean = "car3" />
<ref bean = "car2">
</util:list>

<bean id = "Person2" calss = "com.spring.hellowrld.person">
<property name = "name" value = "Tom"></property>
<property name = "age" value = "22"></property>
<!-- 被引用 -->
<property name = "Cars" ref = "cars">
</property>
</bean>

使用P命名空间

  • 为了简化XML文件的配置,越来越多的XML的XML文件采用属性而飞子元素配置信息。
  • Spring从2.5版本开始引入了一个新的p命名空间,可以通过<bean>元素属性的方式配置Bean的属性。
  • 使用p命名空间后,基于XML的配置方式将进一步简化。
1
2
3
<!-- 通过p命名空间为bean的属性赋值,需要先导入 p 命名空间,相对于传统的配置更加的简洁 -->
<bean id = "person3" class = "com.spring.hellowrld.person" p:age = "30" p:name = "Queen" p:car-ref="cars">
</bean>
-------------本文结束 感谢您的阅读-------------
文章对我有益,我要小额赞赏...