在上一节中,我们已经学会了用Eclipse配置Spring4.0环境并创建一个简单的Spring项目。
在这一节中,将介绍Bean的配置。
本教程使用方法
从前向后阅读,本文较长,建议分9次学完,每次下载当前的代码。
配置形式
基于xml文件的方式,基于注解的方式。
Bean的配置方法
通过全类名(反射)、通过工厂方法(静态工厂方法和实例工厂方法)、FactoryBean
IOC 容器 BeanFactory 和ApplicationContext 概述
在SpringIOC容器读取Bean配置创建Bean实例之前,必须对它进行实例化。只有在容器实例化后,才可以从IOC容器里获取Bean实例并使用。
Spring 提供了两种类型的IOC容器实现。
BeanFactory
IOC容器的基本实现。BeanFactory是Spring 框架的基础设施,面向Spring本身。
ApplicationContext
提供了更多高级的特性,是BeanFactory的子接口。ApplicationContext 面向使用Spring框架的开发者,几乎所有的应用场合都直接使用 ApplicationContext 而非底层的BeanFactory。
无论使用何种方式,配置文件是相同的。
ApplicationContext的主要实现类:(Ctrl+T查看)
-ClassPathXmlApplicationContext:从类路径下加载配置文件
-FileSystemXmlApplicationContext:从文件系统中加载配置文件
ApplicationContext 的子接口ConfigurableApplicationContext,新增加两个主要方法:refresh()和 close(),让ApplicationContext具有启动、刷新和关闭上下文的能力。
ApplicationContext在 初始化上下文 时就 实例化所有单例的Bean。
WebApplicationContext 是专为WEB应用而准备的,它允许从相对于WEB根目录的路径中完成初始化工作。
ApplicationContext的getBean()方法
鼠标放在”ApplicationContext”上按住Ctrl 点击进入 ,
Window-> show view-> outline 查看方法,
其中没有getBean()方法,找到其父接口 ListableBeanFactory ,Ctrl+shit+T 搜索这个父接口,继续用 outline观察它的方法,其中没有getBean()方法,发现它继承了BeanFactory ,继续搜索这个父接口,观察它的方法,找到了getBean()方法。
依赖注入的方式
属性注入;构造器注入;工厂方法注入(不推荐)
属性注入
属性注入即通过setter 方法注入Bean的属性值或依赖的对象。
属性注入使用
属性注入是实际应用中最常用的注入方式。
构造方法注入
构造方法注入属性值或依赖的对象,它保证了Bean实例在实例化以后就可以使用。
构造器注入在<constructor-arg>元素里声明属性,<constructor-arg>中没有name属性。
沿用上一节中的项目。
新建一个类 Car.java。
|
|
配置 applicationContext.xml
|
|
修改 Main.java
|
|
运行,在控制台观察结果。
|
|
注入属性值细节
可以用字符串表示的值,可以通过
若字面值中包含特殊字符,可以使用<![CDATA[]]>把字面值包裹起来。
基本数据类型及其封装类、String等类型都可以采取字面值注入的方式,可以自动类型转换。
null值和级联属性
可以使用专用的
为级联属性赋值
和Struts、Hibernate等框架一样,Spring 支持级联属性的配置。
为级联属性赋值注意:属性要先初始化后才可以为级联属性赋值,否则会有异常。和Struts2不同。
具体见后面程序applicationContext.xml中的例子。
引用其他bean
组成应用程序的Bean经常需要相互协作以完成应用程序的功能,要使Bean能够相互访问,就必须在Bean配置文件中指定对Bean的引用。
在Bean的配置文件中,可以通过元素(标签节点)或ref属性为Bean的属性或构造器参数指定对Bean的引用。
也可以在属性或构造器里包含Bean的声明,这样的Bean称为内部Bean。
新建一个类Person.java。
|
|
修改 Car.java。
|
|
修改applicationContext.xml配置文件。
修改Main.java。
|
|
在控制台观察运行结果。
|
|
集合属性
在Spring中可以通过一组内置的xml标签(例如:<list>,<set>或<map>来配置集合属性)。
配置java.util.List类型的属性,需要指定<list>标签,在标签里包含一些元素,这些标签可以通过<value>指定简单的常量值,通过<ref>指定对其他Bean的引用。通过<bean>指定内置Bean的定义。通过<null/>指定空元素,甚至可以内嵌其他集合。
数组的定义和List一样,都使用<list>。
配置java.util.Set需要使用<set>标签,定义元素的方法与List一样。
新建一个包命名为com.leezp.spring.beans.collections。
在该包下新建一个类 Person.java。
|
|
在该包下新建一个类Main.java。
修改applicationContext.xml配置文件。
|
|
在控制台观察运行结果。
获取源代码
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属性。
在该包下新建一个类 NewPerson.java。
修改applicationContext.xml配置文件。
修改Main.java。
在控制台观察运行结果。
获取源代码
配置Properties属性值。
在com.leezp.spring.beans.collections包下新建一个类 DataSource.java。
|
|
修改applicationContext.xml配置文件。
修改Main.java。
在控制台观察运行结果。
使用 utility scheme定义集合
使用基本的集合标签定义集合时,不能将集合作为独立的Bean定义,导致其他Bean无法引用该集合,所以无法在不同Bean之间共享集合。
可以使用 util schema里的集合标签定义独立的集合Bean。需要注意的是,必须在
先开启Spring配置文件中的util标签:打开applicationContext.xml 配置文件。点击下面的Namespaces,在弹出的复选框中将util复选框勾选。
修改applicationContext.xml配置文件。
|
|
修改Main.java。
|
|
在控制台观察运行结果。
使用 p 命名空间
为了简化XML文件的配置,越来越多的XML文件采用属性而非子元素配置信息。
Spring 从2.5版本开始引入了一个新的 p 命名空间,可以通过
使用p命名空间后,基于XML的配置方式将进一步简化。
修改applicationContext.xml配置文件。
修改Main.java。
在控制台观察运行结果。
自动装配
XML配置里的Bean自动装配
SpringIOC容器可以自动装配Bean。需要做的仅仅是在
byType(根据类型自动装配):若IOC容器中有多个与目标Bean类型一致的Bean,在这种情况下,Spring将无法判定哪个Bean最合适该属性,所以不能执行自动装配。
byName(根据名称自动装配):必须将目标Bean的名称和属性名设置的完全相同。
constructor(通过构造器自动装配):当Bean中存在多个构造器时,此种自动装配方式将会很复杂。不推荐使用。
新建一个包com.leezp.spring.beans.autowire。
在该包下新建Address.java。
在该包下新建Car.java。
在该包下新建Person.java。
|
|
在src下新建一个Spring的配置文件beans-autowire.xml。
|
|
在该包下新建一个Main.java。
在控制台观察运行结果。
XML配置里的Bean自动装配的缺点
在Bean配置文件里设置autowire属性进行自动装配将会装配Bean的所有属性。然而,若只希望装配个别属性时,autowire属性就不够灵活了。
autowire属性要么根据类型自动匹配,要么根据名称自动装配,不能两者兼而有之。
一般情况下,在实际的项目中很少使用自动装配功能,因为和自动装配功能所带来的好处比起来,明确清晰的配置文档更有说服力一些。
在整合第三方框架的时候,使用autowire的确给我们带来一些方便。
bean之间的关系
继承;依赖。
继承Bean配置
Spring允许继承Bean的配置,被继承的Bean称为父Bean,继承这个父Bean的Bean称为子Bean。
子Bean从父Bean中继承配置,包括Bean的属性配置。
子Bean也可以覆盖从父Bean继承过来的配置。
新建一个包com.leezp.spring.beans.relation。
在src下新建一个Spring的配置文件beans-relation.xml。
在该包下新建Main.java。
在控制台观察运行结果。
父Bean可以作为配置模板,也可以作为bean实例,若只想把父bean作为模板,可以设置
并不是
也可以忽略父bean的class属性,让子bean指定自己的类,而共享相同的属性配置。但此时abstract必须设置为true(若某一个bean的class属性没有指定,则该bean必须是一个抽象bean,否则报错)。
修改beans-relation.xml配置文件。
修改Main.java。
在控制台观察运行结果。
依赖Bean配置
Spring允许用户通过depends-on属性设定Bean前置依赖的Bean,前置依赖的Bean会在本Bean实例化之前创建好。
如果前置依赖于多个Bean,则可以通过逗号或空格的方式配置Bean的名称。
使用场景:当bean与bean直接 初始化 有先后顺序时,就需要指定他们直接的依赖关系,可以使用depends-on属性。
修改Car.java。
修改beans-relation.xml配置文件。
|
|
修改Main.java。
在控制台观察运行结果。
bean的作用域
singleton ; prototype ; WEB 环境作用域
singleton:默认值。容器初始化时创建bean实例,在整个容器的生命周期内只创建这一个bean。单例的。
创建Spring配置文件beans-scope.xml。
|
|
修改包com.leezp.spring.beans.autowire下的Car.java。
创建包com.leezp.spring.beans.scope。
在包下创建Main.java。
在控制台观察运行结果。
使用外部属性文件
在配置文件里配置Bean时,有时需要在Bean的配置里混入系统部署的细节信息(例如:文件路径,数据源配置信息等),而这些部署细节实际上需要和Bean配置相分离。
Spring提供了一个PropertyPlaceholderConfigurer的BeanFactory后置处理器,这个处理器允许用户将Bean配置的部分内容外移到属性文件中。可以在Bean配置文件里使用形式为${var}的变量,PropertyPlaceholderConfigurer从属性文件里加载属性,并使用这些属性来替换变量。
Spring还允许在属性文件中使用${propName},以实现属性之间的相互引用。
注册PropertyPlaceholderConfigurer。
Spring2.0:
Spring2.5:
新建beans-properties.xml配置文件。
新建db.properties属性文件。
新建包com.leezp.spring.beans.properties。在该包下新建Main.java。
在控制台观察运行结果。
spEL
Spring表达式或语言(简称SpEL):是一个支持运行时查询和操作对象图的强大的表达式语言。
语法类似于EL:SpEL使用#{…}作为界定符,所有在大括号中的字符都将被认为是SpEL。
SpEL为bean的属性进行动态赋值提供了便利。
通过SpEL可以实现:
1.通过bean的id对bean进行引用。
2.调用方法以及引用对象中的属性。
3.计算表达式的值。
4.正则表达式的匹配。
SpEL:字面量
字面量的表示:
1.整数:<property name=”count” value=”#{5}”/>
2.小数:<property name=”frequency” value=”#{20.1}”/>
3.科学计数法:<property name=”capacity” value=”#{1e3}”/>
4.String可以使用单引号或者双引号作为字符串的界定符号:
<property name=”name” value=”#{‘lee’}“/> 或 <property name=”name” value=’#{“lee”}‘/>
5.Boolean:<property name=”enabled” value=”#{false}”/>
仅仅赋字面值用SpEL的意义不大。重要作用是后面的操作。
SpEL:引用Bean、属性和方法
引用其他对象
1.<!–通过value属性和SpEL配置Bean之间的应用关系–>
<property name=”prefix” value=”#{prefixGenerator}”></property>
2.引用其他对象的属性
<!–通过value属性和SpEL配置 suffix属性值为另一个Bean的suffix–>
<property name=”suffix” value=”#{sequenceGenerator2.suffix}”/>
3.调用其他方法,还可以链式操作
<!–通过value属性和SpEL配置 suffix属性值为另一个Bean的方法的返回值–>
<property name=”suffix” value=”#{sequenceGenerator2.toString()}”/>
<!–方法的连缀–>
<property name=”suffix” value=”{sequenceGenerator2.toString().toUpperCase()}”/>
4.调用静态方法或静态属性
通过T()调用一个类的静态方法,它将返回一个Class Object,然后再调用相应的方法或属性:
<property name=”initValue” value=”#{T(java.lang.Math).PI}”/>
新建一个包com.leezp.spring.beans.spel。
在该包下新建Address.java。
在该包下新建Car.java。
在该包下新建Person.java。
|
|
新建beans-spel.xml配置文件。
|
|
新建Main.java。
在控制台观察运行结果。
SpEL支持的运算符号
1.算数运算符:+,-,*,/,%,^
2.加号还可以用作字符串连接:
<constructor-arg value=”#{performer.firstName+’’+performer.lastName}”/>
3.比较运算符:<,>,==,<=,>=,lt,gt,eq,le,ge
<property name=”equal” value=”#{counter.total==100}”/>
<property name=”hasCapacity” value=”#{counter.total le 10000}”/>
4.逻辑运算符号 and,or,not,!
<property name=”largeCircle” value=”#{shape.kind==’circle’ and shape.perimeter gr<10000}”/>
<property name=”ww” value=”#{!product.available}”/>
<property name=”zz” value=”#{not product.available}”/>
5.if-else运算符(三目运算符) ?:
6.if-else的变体
<constructor-arg value=”#{lee.song} ?: ‘ChunHua’}”/>
7.正则表达式:matches
<constructor-arg value=”#{admin.email matches ‘[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}’}”/>
IOC容器中Bean的生命周期
SpringIOC容器可以管理Bean的生命周期,Spring允许在Bean生命周期的特定点执行定制的任务。
SpringIOC容器对Bean的生命周期进行管理的过程:
1.通过构造器或工厂方法创建Bean实例
2.为Bean的属性设置值和对其他Bean的引用
3.调用Bean的初始化方法
4.Bean可以使用了
5.当容器关闭时,调用Bean的销毁方法
在Bean的声明里设置init-method和destroy-method属性,为Bean指定初始化和销毁方法。
在src下创建包com.leezp.spring.beans.cycle。
在该包下创建Car.java。
创建beans-cycle.xml配置文件。
创建Main.java。
在控制台观察运行结果。
创建Bean后置处理器
Bean后置处理器允许在调用初始化方法前后对Bean进行额外的处理
Bean后置处理器对IOC容器里的所有Bean实例逐一处理,而非单一实例,其典型应用是:检查Bean属性的正确性或根据特定的标准更改Bean的属性。
对Bean后置处理器而言,需要实现Interface BeanPostProcessor接口。在初始化方法被调用前后,Spring将把每个Bean实例分别传递给上述接口的以下两个方法:postProcessBeforeInitialization和postProcessAfterInitialization。
添加Bean后置处理器后Bean的生命周期
SpringIOC容器对Bean的生命周期进行管理的过程:
1.通过构造器或工厂方法创建Bean实例
2.为Bean的属性设置值和对其他Bean的引用
3.将Bean实例传递给Bean后置处理器的postProcessBeforeInitialization方法
4.调用Bean的初始化方法
5.将Bean实例传递给Bean后置处理器的PostProcessAfterInitialization方法
6.Bean可以使用了
7.当容器关闭时,调用Bean的销毁方法
修改Car.java。
新建MyBeanPostProcessor.java。
|
|
修改beans-cycle.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="car" class="com.leezp.spring.beans.cycle.Car"
init-method="init" destroy-method="destroy">
<property name="brand" value="Audi"></property>
</bean>
<!-- 实现BeanPostProcessor接口,并具体提供两个方法的实现 -->
<!-- 配置Bean的后置处理器 -->
<bean class="com.leezp.spring.beans.cycle.MyBeanPostProcessor"></bean>
</beans>
在控制台观察运行结果。
Car's Constructor...
setBrand...
postProcessBeforeInitializationCar [brand=Audi],car
init...
postProcessAfterInitializationCar [brand=Audi],car
Car's Constructor...
setBrand...
Car [brand=Ford]
destroy...
版权声明:本文为博主原创文章,转载请注明出处 Leezp’s Blog