Spring装配
在spring容器内拼凑bean叫作装配。装配bean的时候,你是在告诉容器,
需要哪些bean,以及容器如何使用依赖注入将它们配合在一起。
理论上,bean装配可以从任何资源获得,包括属性文件,关系数据库
等,但xml是最常见的spring 应用系统配置源。Spring中的几种容器都支
持使用xml装配bean,包括:
XmlBeanFactory ,
ClassPathXmlApplicationContext ,
FileSystemXmlApplicationContext ,
XmlWebApplicationContext
基本的xml配置包括如下几个方面:
1.添加一个bean
2.设置bean的属性
2.1 手动设置
2.1.1 通过Setter方法
2.1.2 通过构造器
2.2 自动设置
其中bean的属性即为bean里的成员变量,这些成员变量值的获得可以
通过 setter方法,例如某个属性为name,则setter方法为setName(String
name);或者通过构造器在类被实例化时初始化。Setter方法(例如
setName方法)或者构造器的调用都可以通过在xml文件里进行配置,从而
实现让spring容器来自动进行。
1.添加一个bean
以下是一个例子:
<bean
id = “mybean”
Class = “blog.spring.MyBean”
Singleton = “false”
init-method = “initMethod”
destroy-method = “destroyMethod”
autowire = “autowire type”
/> id = “mybean”
Class = “blog.spring.MyBean”
Singleton = “false”
init-method = “initMethod”
destroy-method = “destroyMethod”
autowire = “autowire type”
/>
下面是对该标签里各个属性的解释:
Id : 标识该bean的名称,通过factory.getBean(“id”)来获得实例
。
Class : 该bean的类路径。
Singleton : 默认为true,即单实例模式,每次getBean(“id”)时
获取的都是同
一个实例,如果设置为false,即原型模式,则每次获取的是新创建
的实例。
Init-method : 在bean实例化后要调用的方法(bean里定义好的方法)
。
Destroy-method : bean从容器里删除之前要调用的方法。
Autowire : 其属性要通过何种方法进行属性的自动装配。
对于上述的各个属性,id和class是必要的,其他的则可以省略。例
如如果设置了autowire的值,则表明需要自动装配,否则是手动装配。
2.通过Setter方法手动设置bean里的属性
Bean里的属性通过<property>标签来标识。有以下几种情况:
● 简单类型属性
<bean id = “mybean” class = “blog.spring.MyBean”>
<property name = “name”>
<value>springTest</value>
</property>
</bean>
● 引用其他bean
<bean id = “mybean” class = “blog.spring.MyBean” />
<bean id = “mybean1” class = “blog.spring.MyBean1”>
<property name = “name”>
<ref bean = “mybean” />
</property>
</bean>
也可以将<ref>改为
<bean class = “..”>
这样叫做内部bean,缺点是无法在其他地方重用这个bean的实例。
● 装配集合
共有以下几种集合的装配:
****装配List和数组****
<property name = ”nameList”>
<list>
<value>something</value>
<ref bean = “blog.spring.MyBean” />
<value>otherThing</value>
</list>
</property>
****装配Set****
<property name = ”nameList”>
<set>
<value>something</value>
<ref bean = “blog.spring.MyBean” />
<value>otherThing</value>
</set>
</property>
****装配Map****
<property name = ”nameList”>
<map>
<entry key = “key1”>
<value>value1</value>
</entry>
<entry key = “key2”>
<ref bean = “mybean” />
</entry>
</map>
</property>
****装配Properties****
<property name = ”nameList”>
<props>
<prop key = “prop1”>value1</prop>
<prop key = “prop2”>value2</prop>
</props>
</property>
● 设置null
要将一个属性null,需要通过<null />标签,如果不设置,则属性为
默认值(在实例化时)而不是null。
<property name=”name”><null /> </property>
3.通过构造器手动设置bean里的属性
假设有如下一个bean:
Public class MyBean {
Public MyBean( String arg1, MyBean1 arg2, String arg3 )
}
则可以在xml里这样配置该bean:
<bean id = “mybean” class = “blog.spring.MyBean”>
<constructor-arg index = “1”>
<value>springTest</value>
<constructor-arg>
<constructor-arg index = “0”>
<ref bean = “mybean1” />
<constructor-arg>
</bean>
其中的index是用来标识该参数在构造函数里的位置的,并从0开始。
4.让spring完成自动装配
例如:
<bean
id = “mybean”
class = “blog.spring.MyBean”
autowire = “autowire type”
/> id = “mybean”
class = “blog.spring.MyBean”
autowire = “autowire type”
/>
下面是几种autowire type的说明:
● byname : 试图在容器中寻找和需要自动装配的属性名相同的bean
或id,如果没有找到相应的bean,则这个属性未被装配上。
● byType : 试图在容器中寻找一个与需要自动装配的属性类型相同
的bean或id,如果没有找到,则该属性未被装配上。
● constructor : 试图在容器中寻找与需要自动装配的bean的构造
函数参数一致的一个或多个bean,如果没找到则抛出异常。
● autodetect : 首先尝试使用constructor来自动装配,然后再使
用byType方式。
从上面可以看出,如果某个bean不手动设置autowire属性,则默认为
手动装配。如果需要将所有bean都设置为自动装配时,可以通过在
<beans>标签中设置default-autowire属性。<beans>标签是整个xml文档
的根,在它下面就是一个个的<bean>。
其中default-autowire的值也有byName,byType,constructor,
autodetect四种。
例如配置如下:
<beans default-autowire = “byName”>
...
</beans>
自动装配可能带来不确定性问题。例如使用byType时可能同时发现两
个相同的类型,则不知道该采用哪一个。所以可能混合采用自动和手动装
配。例如,对某个bean设置为自动装配,而对其某个属性则手动明确的设
置其值,例如:
<bean id = “mybean” class = “blog.spring.MyBean”
Autowire = “byType”
> Autowire = “byType”
>
<property name = “name”>
<ref bean = “myBean1”>
</property>
</bean>
通过这样的配置,对mybean里的name属性进行手动装配,而对除name
外的其他属性就进行自动装配。
================================================================
==================
另一篇文章相关:
Spring ApplicationContext.xml配置的12个技巧
Spring是一个强有力的java程序框架,其被广泛应用于java的程序中。它
用 POJO提供了企业级服务。 Spring利用依赖注入可以获得简单而有效的
测试能力。Spring beans,依赖关系,以及服务所需要的bean都将在配置
文件中予以描述,配置文件一般采用XML格式。然而XML配置文件冗长而不
易使用,在你进行一 个使用了大量bean的大项目中它将变得难以阅读和
控制。
在这篇文章中我将给你展示12种的有关Spring XML配置文件的最佳技巧。
它们中的一些具有更多的实际意义,而不仅是最好的技巧。请注意另外一
些因素,例如域模型的设计,会影响到XML配置,但是这篇文章更关注于
XML配置的可读性和可操控性。
1.避免使用自动装配
Spring 可以通过bean类的自省来实现自动装配依赖,这样的话你就不必
明确地描述bean的属性或者构造函数的参数。根据属性名称活匹配类型,
bean属性可以 自动进行装配。而构造函数可以根据匹配类型自动装配。
你甚至可以设置自动装配进行自动侦测,这样Spring替你就会选择一个合
适的机制。请看下面的例 子:
Spring 可以通过bean类的自省来实现自动装配依赖,这样的话你就不必
明确地描述bean的属性或者构造函数的参数。根据属性名称活匹配类型,
bean属性可以 自动进行装配。而构造函数可以根据匹配类型自动装配。
你甚至可以设置自动装配进行自动侦测,这样Spring替你就会选择一个合
适的机制。请看下面的例 子:
<bean id="orderService"
value="lizjason"/>
<constructor-arg index="1" value="100"/>
</bean>
最好用type属性取代上面的做法:
<bean id="billingService"
value="100"/>
</bean>
用index可以稍微减少冗余,但是它更容易出错且不如type属性可读性高
。你应该仅在构造函数中有参数冲突时使用index。
5.如可能,尽量复用bean定义
Spring 提供了一种类似于继承的机制来降低配置信息的重复并使XML配置
更加的简单。一个子bean可以从它的父bean继承配置信息,本质上这个父
bean就像 它的子bean的一个模板。这是一个在大型项目中必须使用的特
性。所有你要做的就是把父bean的abstract属性置为true,并在子bean中
加 以引用。例如:
<bean id="abstractService" abstract="true"
value="lizjason"/>
</bean>
shippingService bean继承了abstractService bean的属性companyName
的值lizjason。注意,如果你为bean声名一个class或工厂方法,这个
bean将会默认为abstract
6.
尽量使用
ApplicationContext
装配bean,而不是用import
像Ant脚本中imports一样,
Spring的
import
元素对于模块化bean的装配非常有用,例如:
<beans>
<import resource="billingServices.xml"/>
<import resource="shippingServices.xml"/>
<bean id="orderService"
scope="singleton"/>
这里的scope就是用来配置spring bean的作用域,它标识bean的作用域。
在spring2.0之前bean只有2种作用域即:singleton(单例)、non-
singleton(也称 prototype), Spring2.0以后,增加了session、
request、global session三种专用于Web应用程序上下文的Bean。因此,
默认情况下Spring2.0现在有五种类型的Bean。当然,Spring2.0对 Bean
的类型的设计进行了重构,并设计出灵活的Bean类型支持,理论上可以有
无数多种类型的Bean,用户可以根据自己的需要,增加新的Bean类 型,
满足实际应用需求。
1、singleton作用域
当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在
一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹
配,则只会返回bean的同一实例。换言之,当把 一个bean定义设置为
singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。
这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针
对该bean的后续请求和引用都 将返回被缓存的对象实例,这里要注意的
是singleton作用域和GOF设计模式中的单例是完全不同的,单例设计模式
表示一个ClassLoader中 只有一个class存在,而这里的singleton则表示
一个容器对应一个bean,也就是说当一个bean被标识为singleton时 候,
spring的IOC容器中只会存在一个该bean。
配置实例:
<bean id="role"
scope="singleton"/>
或者
<bean id="role"
singleton="true"/>
2、prototype
prototype作用域部署的bean,每一次请求(将其注入到另一个bean中,
或者以程序的方式调用容器的
getBean()
方法)都会产生一个新的bean实例,相当与一个new的操作,对于
prototype作用域的bean,有一点非常重要,那就是Spring不能对一个
prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是
装配完一个prototype实例后,将它交给客户端,随后就对该prototype实
例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周
期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法
都将不会被调用。 清除prototype作用域的对象并释放任何prototype
bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被
singleton作用域bean占用资源的一种可行方式是,通过使用 bean的后置
处理器,该处理器持有要被清除的bean的引用。)
配置实例:
<bean id="role"
scope="prototype"/>
或者
<beanid="role"
singleton="false"/>
3、request
request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean
仅在当前HTTP request内有效,配置实例:
request、session、global session使用的时候首先要在初始化web的
web.xml中做如下配置:
如果你使用的是Servlet 2.4及以上的web容器,那么你仅需要在web应用
的XML声明文件web.xml中增加下述ContextListener即可:
<web-app>
...
<listener>
<listener-
class>org.springframework.web.context.request.RequestContextList
ener</listener-class>
</listener>
...
</web-app>
,如果是Servlet2.4以前的web容器,那么你要使用一个
javax.servlet.Filter的实现:
<web-app>
..
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-
class>org.springframework.web.filter.RequestContextFilter</filte
r-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
</web-app>
接着既可以配置bean的作用域了:
<bean id="role"
scope="request"/>
4、session
session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时
该bean仅在当前HTTP session内有效,配置实例:
配置实例:
和request配置实例的前提一样,配置好web启动文件就可以如下配置:
<bean id="role"
scope="session"/>
5、global session
global session作用域类似于标准的HTTP Session作用域,不过它仅仅在
基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概
念,它被所有构成某个 portlet web应用的各种不同的portlet所共享。
在global session作用域中定义的bean被限定于全局portlet Session的
生命周期范围内。如果你在web中使用global session作用域来标识bean
,那么web会自动当成session类型来使用。
配置实例:
和request配置实例的前提一样,配置好web启动文件就可以如下配置:
<bean id="role"
scope="global session"/>
6、自定义bean装配作用域
在spring2.0中作用域是可以任意扩展的,你可以自定义作用域,甚至你
也可以重新定义已有的作用域(但是你不能覆盖singleton和 prototype
),spring的作用域由接口
org.springframework.beans.factory.config.Scope来定 义,自定义自
己的作用域只要实现该接口即可,下面给个实例:
我们建立一个线程的scope,该scope在表示一个线程中有效,代码如下:
publicclass MyScope implements Scope ...{
privatefinal ThreadLocal threadScope = new ThreadLocal()
...{
protected Object initialValue() ...{
returnnew HashMap();
}
};
public Object get(String name, ObjectFactory objectFactory)
...{
Map scope = (Map) threadScope.get();
Object object = scope.get(name);
if(object==null) ...{
object = objectFactory.getObject();
scope.put(name, object);
}
return object;
}
public Object remove(String name) ...{
Map scope = (Map) threadScope.get();
return scope.remove(name);
}
publicvoid registerDestructionCallback(String name,
Runnable callback) ...{
}
public String getConversationId() ...{
// TODO Auto-generated method stub
returnnull;
}
}