Spring配置文档类型
Spring2.0
前只有
DTD
格式
,Spring2.X
依旧支持这种格式
,
但它更推荐使用基于
Schema
格式
.Schema
格式让不同类型的配置拥有了自己的的命名空间
,
使配置文件更具扩展性
.
DTD
格式:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC “-//SPRING/DTD BEAN 2.0//EN”
“http://www.springframework.org/dtd/spring-beans-2.0.dtd”>
<beans>
<bean id=”foo” class=”com.baby.Foo”>
</beans>
Schema
配置格式
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframeword.org/schema/benas"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocaation=
"http://www.springframework.org/schema/beans
http://www.pringframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean id="foo" class="baby.Foo">
<aop:config>
<aop:adivsor pointcut="execution(**..PetStoreFacade.*(..))" advice-ref="txAdvice"/>
</aop:config>
<benas>
大家可以看到Schema的配置声明比DTD的要复杂的多,但它能提供更好的扩展性和简化配置工作(怎样简化在后面会看到)
下面我们来了解下
Schema
的配置文档.
第一步是指定命名空间的别名和全名,也就是上面的xmlns的部分.
只有xmlns表示没有命名空间,也就是默认命名空间,它用于Spring Bean的定义;
xmlns:xsi表示xsi命名空间,用于为每个文档中的命名空间指定相应的Schema样式文件;
xmlns:aop表示aop命名空间,它是Spring配置aop的命名空间
xmlns:aop=”http://www.springframework.org/schema/aop”
别名
全名
习惯上用文档发布机构的官网地址和相关目录作为全名,而
实际上别名和全名可以用任意名字
.
第二步,为每个命名空间指定对应的Schema文档格式定义文件, 也就是上面的xsi:schemaLocaation的部分,一般
使用发布机构提供的
URL
地址指定命名空间对应的Schema
文件.不同的命名空间之间用空格或回车分隔.
下表显示了Spring2.0提供的Schema
Spring2.0提供的Schema
目
录
|
说
明
|
spring-beans-2.0.xsd
|
Spring2.0
最主要的
Schema,
用于配置
bean
|
spring-aop-2.0.xsd
|
为简化
AOP
的配置定义的
Schema
|
spring-tx-2.0.xsd
|
为简化声明事务配置定义的
Schema
|
spring-until-2.0.xsd
|
为简化某些复杂的标准配置提供的
Schema
|
spring-jee-2.0.xsd
|
为简化
JAVA EE
中
EJB,JNDI
等到功能的配置而提供的
Schema
|
spring-lang-2.0.xsd
|
Spring2.0
增加了对
Jruby
和
Groovy
等动态语言的支持,它是为集成动态语言而定义的
|
spring-test.xsd
|
为测试定义的
Schema
|
spring-tool-2.0xsd
|
为集成
Spirng
一些有用的工具定义的
Schema
|
Bean基本配置
装配一个简单Bean:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframeword.org/schema/benas"
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocaation=
"http://www.springframework.org/schema/beans http://www.pringframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="foo" class="com.baby.Foo"/>
<benas>
Bean的命名
Id在Ioc容器中必须是唯一的,它必须以字母开始,后面可以是字母、数字、连字符、下划线、句号、冒号等完全结束符。还有一个属性name,其和id差不多,但它对名字没有限定,且其值是可以重复的。
多个子name相同的<bean>在获取Bean时(getBean(beanName))将返回最后一个Bean,所以
建议使用而不要使用
name
还有一种无名Bean如:
<bean class=”com.baby.Foo”>,那么它的名字就是其全限定类名”com.baby.Foo”,自然是用getBean(“com.baby.Foo”)得到。
如果有多个全限定类名相同的Bean第一个用getBean(“com.baby.Foo”)得到,第二个用getBean(“com.baby.Foo
#1”)获得,以此类推。
依赖注入
Spring支持属性注入,构造函数注入和工厂方法注入。
属性注入
属性注入即通过setXxx()方法注入Bean的属性值或依赖对象
如:
Public class Foo{
private String color;
private int size;
public void setColor(String color) {
this.color = color;
}
public void s
etSize(int size) {
this.size = size;
}
}
配置:
<bean id=”foo” class=”com.baby.Foo”>
<property name=”color”><value>红色</value></property>
<property name=”size”><value>10</value></property>
</bean>
构造函数注入
在Foo类中加个构造函数
public Foo(String color, int size) {
this.color = color;
this.size = size;
}
配置文件中用<constructor-arg>来配置。我们看到Foo的构造函数有多个参数,那么我们用什么来指定给的值是对应哪个参数呢?
在<constructor-arg>标签中有type和index 两个属性可以区别,type是代表参数的类型,index 是代表参数的索引(从0开始)
<bean id=”foo” class=”com.baby.Foo”>
<constructor-arg index=”0” type=”java.lang.String”><value>红色</value><constructor-arg>
<constructor-arg index=”1” type=”int”><value>10</value><constructor-arg>
</bean>
有时用一个属性就能明确区分,但如果有多个构造函数且参数个数相同但类型不同时就只能同时用两个属性才能区分。
工厂方法注入
工厂方法主要是处理遗留系统或第三方类库中的工厂方法,一般新开发的系统不建议用这种方法。
工厂方法有两种,一种是非静态工厂方法,一种是静态工厂方法。它们在配置上的唯一区别是非静态工厂方法要多配置一个工厂Bean.如:
非静态工厂方法
<bean id=”fooFactory” class=”com.baby.FooFactory”/>
<bean id=”foo”
factory-bean=”fooFactory” factory-method=”createFoo”/>
静态工厂方法
<bean id=”foo”
class=”com.baby.FooFactory” factory-method=”createFoo”/>
注入参数详解
字面值
基本数据类型及其封闭类,String等类型都可以采取字面值注入的方式.要注意的是
XML
特殊实体符号
如果字面值中包含有XML特殊实体符号可以有两个方法进行处理,一种是用转义序列,一种是用
<![CDATA[]]>特殊标签.
如:
<bean id=”car” class=”com.baby.Car”>
<property name=”maxSpeed”>
<value>200</value>
</property>
<property name=”brand”>
<value><![CDATA[
红旗&CA&2]]></value>
</property>
</bean>
<![CDATA[]]>
的的作用是让XML
解析器将标签中的字符串当作普通的文本对待.
以上的特殊字符还可以用转义序列表示: <value>
红旗&CA&2</value>
XML特殊实体符号
特殊符号
|
转义序列
|
特殊符号
|
转义序列
|
<
|
<
|
“
|
"
|
>
|
>
|
‘
|
'
|
&
|
&
|
|
|
引用其他Bean
如果一个Bean中的一个属性是另一个Bean那么在配置文件中就用<ref>元素引用这个Bean.
如Boss类中有个Car类的属性,那么配置文件是:
<bean id=”car” class=”com.baby.Car”/>
<bean id=”boss” class = “com.baby.Boss”>
<property name= “car”>
<ref bean=”car”/>
</property>
</bean>
<ref>元素可以以以下三个属性引用容器中其他Bean:
l bean:通过该属性可以引用同一
容器或父容器的Bean,这是最常见的形式;
l local: 通过该属性可以引用同一
配置文件中定义的Bean,它可以利用XML解析器自动检验引用的合法性,以便在开发编写配置时能够及时发现并纠正配置的错误.
l parent:引用
父容器中的Bean.
内部Bean
内部Bean是在如果你想让一个Bean不被容器中其他Bean所引用时使用.
如:Car只被Boss引用,不能被其他Bean引用:
<bean id=”boss” class = “com.baby.Boss”>
<property name= “car”>
<bean class=”com.baby.Car”>
<property name=”maxSpeed” value=”200”/>
</bean>
</property>
</bean>
内部Bean的Scope属性默认为
prototype
类型
null值
如果要想把一个属性的值给null是要用
<null/>元素标签而不是写null
如:<property name=”maxSpeed”><null/></property>
级联属性
前面已经多次说到了Boss类中有个Car类属性,那么通过级联属性可以直接对Car中的属性进行值注入:
<bean id=”boss” class=”com.baby.Boss”>
<property name=”car.maxSpeed” value=”200”/>
</bean>
级联用”.”
实现.那么Spring就会以Boss.getCar().setMaxSpeed(200)来进行属性的注入.
当然级联有个前提下:
在Boss类的Car类属性
一定要进行初始化
,如:private Car car = new Car();否则会抛出NullValueInNestedPathExcepin异常
集合类型属性
Spring对java.util中的集合类进行了完全的支持.
List
<bean id=”boss” class=”com.baby.Boss”>
<property name=”favorites”>
<list>
<value>看报</value>
<value>听歌 </value>
</lsit>
</property>
</bean>
数组也用list
进行设置
Set
<bean id=”boss” class=”com.baby.Boss”>
<property name=”favorites”>
<set>
<value>看报</value>
<value>听歌 </value>
</set>
</property>
</bean>
Map
<bean id=”boss” class=”com.baby.Boss”>
<property name=”jobs”>
<map>
<entrty>
<key><value>12:00</value></key>
<value>听歌</value>
</entrty>
</map>
</property>
</bean>
Property
<bean id=”boss” class=”com.baby.Boss”>
<property name=”mails”>
<props>
</ props >
</property>
</bean>
强类型集合
在JDK5.0提供了强类型集合如:private Map<String, Integer> map= new Map<String, Integer>配置和一般的一样只是在注入时会判断元素的类型.
集合合并
<bean id=”parentboss” class=”com.baby.Boss”
abstract=”true”>
<property name=”favorites”>
<list>
<value>看报</value>
<value>听歌 </value>
</lsit>
</property>
</bean>
<bean id=”childboss” class=”com.baby.Boss” parent=”parentBoss”>
<property name=”favorites”>
<list merge=”true”>
<value>足球</value>
<value>游泳</value>
</lsit>
</property>
</bean>
merge=”true”
指了<bean>
和父<bean>
中同名属性值进行合并
简化配置方式
直接量
<property name=”maxSpeed” value=”200”/>
<constructor-arg type=”java.lang.String” value=”CAVD”/>
<map>
<entry key=”AM” value=”
游泳”/>
</map>
引用其他Bean
<property name=”car” ref=”car”/>
<constructor-arg ref=”car”/>
<map>
<entry key-ref=”keyBean” value-ref=”valueBean”/>
</map>
简化形式对应于<ref bean=”xxxx”>,
而<ref local=”xxx”>
和<ref parent=”xxx”>
没有简化形式
方法注入
如果我们往singleton的Bean(Boss)中注入prototype的Bean(Car),并希望每次调用Boss Bean的getCar()时能返回一个新的Car Bean,使用传统的注入方式是不可能实现的.那么可能用两种方式实现:
一种是Boss类实现BeanFactoryAware接口,这样getCar()将用return (Car)factory.getBean(“car”)实现.但这种方式和Spring结合的太紧密,所以建议使用第二种方法:”方法注入”
lookup方法注入
方法注入是通过CGLib类包,在运行时动态的操作Class字节码实现,所以在使用时要加载此包.配置文件如下:
<bean id=”boss” class=”com.baby.Boss”>
<lookup-method name=”getCar” bean=”car”/>
</bean>
<bean>之间的关系
继承
<bean id=”abstractCar” class=”com.baby.Car”
abstract=”true”>
--定义为抽象<bean>
<property name=”maxSpeed” value=”200”/>
<property name=”color” value=”red”/>
</bean>
<bean id=”car1” class=”com.baby.Car”
parent=”abstractCar”>
--继承开abstractCar
<property name=”color” value=”red”/>
</bean>
“car1”将继承”abstractCar”的全部配置信息.
abstract=”true”
表示这个<bean>
是不会实例化的
依赖
虽然Spring会在bean实例化时先初始化其依赖的Bean,如<ref>但有些Bean之间的依赖关系不那么明显,那么就要显示的告诉Spring依赖关系,以保证在Bean实例化时其所以依赖的Bean都初始化了.这个就要用到
depends-on属性来指定依赖的Bean
<bean id=”boss” class=”com.baby.Boss” depends-on=”car”/>
如果一个Bean
有多个前置Bean
则用逗号,
空格或分号分开
引用
如果一个<bean>的属性值是另一个<bean>的id值则要用到
<idref>
元素标签
<bean id=”boss” class=”com.baby.Boss” >
<property name=”carid”>
<idref bean=”car”/>
</property>
</bean>
Bean作用域
Bean作用域类型
类别
|
说
明
|
singleton
|
在
Spring IoC
容器中仅存在一个
Bean
实例
,Bean
以单例的方式存在
|
prototype
|
每次从容器中调用
Bean
时
,
都返回一个新的实例
.
|
request
|
每次
Http
请求都会创建一个新的
Bean
|
session
|
同一个
HTTP Session
共享一个
Bean
|
globalSession
|
同一个全局
Session
共享一个
Bean,
一般用于
Portlet
环境
|
singleton
<bean id=”car” class=”com.baby.Car”
scope=”singleton”/>
Spring的ApplicationContext容器在启动时会自动实例化所有的sinleton的Bean并缓存于容器中.如果想在启动时不实例化可以加上lazy-init属性
<bean id=”car” class=”com.baby.Car”
lazy-init=”true”/>
prototype
<bean id=”car” class=”com.baby.Car”
scope=”prototype”/>
Spring容器启动时不会实例化prototype的Bean.Spring容器将prototype的Bean实例化后就不再管理它的生命周期了.
Web应用环境相关的Bean作用域
要使用WebApplicationContext提供的三种作用域必然在此Web容器的配置:
低版本Web容器中的配置(Servlet2.3前),使用HTTP请求过滤器
<web-app>
……
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
高版本Web容器中的配置,利用HTTP请求监听器配置
<web-app>
……
<listener>
<listener-class>
Org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
</web-app>
在web中配置Spring时我们用了ContextLoaderListener监听器,那么它和现在的RequestConextListener有什么区别呢?
ContextLoaderListener
实现了ServletContextListener
监听接口,ServletContextListener
只负责监听Web
容器启动和关闭的事件,
而RequestContextListener
实现ServletRequestListener
监听器接口,
该项监听器监听HTTP
请求事件,Web
服务器接收的每一次请求都会通知该监听器.
作用域依赖问题
将Web相关作用域Bean注入到非Web相关作用域中时要
使用
aop
代理,否则将无法实现
<?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:aop=”http://www.springframework.org/schema/aop”
xsi:schemaLocation=”http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
hhtp://www.springframework.org/schema/aop/spring-aop-2.0.xsd”>
<bean name=”car” class=”com.baby.Car” scope=”request”>
<aop:scoped-proxy/>
</bean>
<bean id=”boss” class=”com.baby.Boss”
<property name=”car” ref=”car”/>
</bean>
</beans>