Spring为Java大地带来了一阵春风,它作为一个优秀的轻量级企业应用开发框架,能够大大简化企业应用开发的复杂性。

Spring以IoC(或DI)和AOP这两样先进的设计理念为基础,统一了应用对象的查找、配置和生命周期的管理,分离了业务与基础服务中的不同关注点,开发人员可以基于简单Java对象轻松的实现与EJB同样强大的功能。

对于spring框架,做web开发的开发人员应该都很了解,其配置量也是蛮大的。不过,基于spring3.0后,为了减少配置带来不必要的不便,逐渐提倡注解的方式了。但是作为其xml配置文件还是必须要掌握的,注解也不是全能的,任何事务都是有两面性的。

下面我们来了解一下spring的配置文件中的基本属性及参数吧。

1、value元素

<value/>元素通过字符串来指定属性或构造器参数的值。


2、idref元素

idref元素用来将容器内其它bean的id传给<constructor-arg/>或<property/>元素。

<bean id="theTargetBean" class="..."/>
<bean id="theClientBean" class="...">
<property name="targetName">
<idref bean="theTargetBean" />
</property>
</bean>
等同于:

<bean id="theTargetBean" class="..." />
<bean id="theClientBean" class="...">
<property name="targetName">
<value>theTargetBean</value>
</property>
</bean>

使用idref标记允许容器在部署时验证所被引用的bean是否存在。此外,如果被引用的bean在同一XML文件内,且bean名字就是bean id,那么可以使用local属性。

此属性允许XML解析器在解析XML文件时来对引用的bean进行验证。

<property name="targetName">
<idref local="theTargetBean" />
</property>

3、ref元素

形式一:<ref bean="someBean">

这是最常见的形式是通过使用ref标记指定bean属性的目标bean,通过该标签可以引用同一容器或父容器内的任何bean(无论是否在同一XML文件中)。

XML‘bean’元素的值即可以是指定的bean的id值也可以是其name值。

形式二:<ref local="someBean">

使用ref的local属性指定目标bean,它可以利用XML解析器来难所引用的bean是否存在同一文件中。local属性值必须是目标bean的id属性值。

形式三:<bean parent="someBean">

通过使用ref的parent属性来引用当前窗口的父容器中的bean。parent属性值即可以是目标bean的id值,也可以是name属性值。

4、内部 bean


所谓内部bean(inner bean)是指在一个bean的<property/>或<constructor-arg/>中使用< bean/>元素定义的bean.内部bean不需要有id或name属性,即使有也会被窗口忽略.

内部bean总是匿名的且它们总是prototype模式的.同时将内部bean注入到包含该内部bean之外的bean是不可能的.

<bean id="outer" class="...">
<property name="target">
<bean class="com.mycoompany.Person">
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</bean>

5、集合合并


从Spring2.0开始,Spring IoC容器将支持集合的合并。父子集合元素合并后的值就是子集合中的最终结果,而且子集合中的元素值将覆盖父集合中的对应的值。

<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop key="administrator">administrator@somecompany.com</prop>
<prop key="support">support@somecompany.com</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property name="adminEmails">
<props merge="trur">
<prop key="sales">sales@somecompany.com</prop>
<prop key="support">support@somecompany.co.uk</prop>
</props>
</property>
</bean>
</beans>

list集合有排序功能,父bean的列表内容将排在子bean列表内容的前面;

merge属性必须在继承的子bean中定义。

6、Nulls


<null/>用于处理null值。Spring会把属性的空参数当作空字符串处理。

<bean class="ExampleBean">
<property name="email">
<value></value>
</property>
</bean>
等同于

excapleBean.setEamil("");


而null值则可以使用<null/>元素来表示:

<bean class="ExampleBean">
<property name="email"><null/></property>
</bean>


7、简写

针对常见的value值或bean的引用,Spring提供了简化格式用于替代<value/>和<ref/>元素。

<property/>、<constructor-arg/>、<entry/>元素都支持value属性,它可以用来替代内嵌的<value/>元素。

<property name="myProperty"> 
<value>hello</value> 
</property>
等同于  <property name="myProperty" value="helo" />
<constructor-arg>
<value>hello</value> 
</construtctor-arg>
等同于  <constructor-arg value="hello" />
<entry key="myKey">
<value>hello</value> 
</entry>
等同于 <entry key="myKey" value="hello" />

<property/>和<constructor-arg/>支持类似的简写属性ref,它可以替找整个内嵌的</ref>元素。

<property name="myProperty">
<ref bean="myBean">
</property>
 等同于 <property name="myProperty" ref="myBean" />
<constructor-arg>
<ref bean="myBean"> 
</constructor-arg>
等同于 <constructor-arg ref="myBean" />


切记:尽管存在等同于<ref bean="xxx" >元素的简写形式,但并没有<ref local="xxx">的简写形式。


map中的entry元素的简写形式为key/key-ref和value/value-ref属性。

<entry>
<key>
<ref bean="myKeyBean" />
</key>
等同于 <entry key-ref="myKeyBean" value-ref="myValueBean" />

<ref bean="myValueBean" />
</entry>

8、组合属性名称

当设置bean的组合属性时,除了最后一下属性外,只要其他属性值不为null,组合或嵌套属性名是完全合法的。

<bean id="foo" class="foo.Bar">
<property name="fred.bob.sammy" value="123" />
</bean>

9、depends-on属性

depends-on属性可以用于当前bean初始化之前显式的强制一个或多个bean被初始化。

<bean id="beanOne" class="ExampleBean" depends-on="manager">
<property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />

若需要表达对多个bean的依赖,可民认在<depends-on />中将指定的多个bean名字用分隔符进行分隔,分隔符可以是逗号、空格及分号等。

<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />

10、延迟初始化bean--lazy-init 属性

<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true">
 ...
</bean>
<bean name="noo.lazy" class="com.foo.AnotherBean">
 ...
</bean>

如 果一个bean被设置为延迟初始化,而另一个非延迟初始化的singleton bean依赖于它,那么当ApplicationContext提前实例化singleton bean时,它必须也确保所有上述singleton依赖bean也被预先初始化,当然也包括设置为延迟实例化的bean.


在容器层次中通过在<beans />元素上使用‘default-lazy-init’属性来控制延迟初始化也是可能的。

<beans default-lazy-init="true">

...

</beans>

11、autowire<自动装配> 属性

模式  说明

no 不使用自动装配,必须通过ref元素指定依赖,这是默认设置。

byType 如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。如果存在多个,则抛出异常。

byName 根据属性名自动装配。Spring将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配。

constructor  与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中未找到与构造器参数类型一致的bean,那么将抛出异常。

autodetect   通过bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式。


通过设置<bean />元素的autowire-candidate="false",可以针对单个bean设置其是否为被自动装配对象。


12、dependency-check <依赖检查> 属性

此属性用于检查bean定义中实际属性值的设置。



模式  说明

none   没有依赖检查,如果bean的属性没有值的话可以不用设置。

simple  对于原始类型及集合(除协作者外的一切东西)执行依赖检查。

object  仅对协作者执行依赖检查员。

 all   对协作者,原始类型及集合执行依赖检查。

spring事务配置

前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识。通过这次的学习发觉Spring的事务配置只要把思路理清,还是比较好掌握的。


总结如下:


Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分。


DataSource、TransactionManager这两部分只是会根据数据访问方式有所变化,比如使用Hibernate进行数据访问时,DataSource实际为SessionFactory,TransactionManager的实现为HibernateTransactionManager。


根据代理机制的不同,总结了五种Spring事务的配置方式,配置文件如下:


第一种方式:每个Bean都有一个代理

< bean  id ="sessionFactory"  
class ="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
< property  name="configLocation"  value="classpath:hibernate.cfg.xml"  /> 
< property  name="configurationClass"  value="org.hibernate.cfg.AnnotationConfiguration"  />
</ bean> 

<!-- 定义事务管理器(声明式的事务) -->  
< bean  id="transactionManager"
class ="org.springframework.orm.hibernate3.HibernateTransactionManager">
< property  name="sessionFactory"  ref="sessionFactory"  />
</ bean>

<!-- 配置DAO -->
< bean  id="userDaoTarget"  class="com.bluesky.spring.dao.UserDaoImpl">
< property  name="sessionFactory"  ref="sessionFactory"  />
</ bean>

< bean  id="userDao"  
class ="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">  
<!-- 配置事务管理器 -->  
< property  name="transactionManager"  ref="transactionManager"  />  
< property  name="target"  ref="userDaoTarget"  />  
< property  name="proxyInterfaces"  value="com.bluesky.spring.dao.GeneratorDao"  />
<!-- 配置事务属性 -->  
< property  name="transactionAttributes">  
< props>  
< prop  key="*"> PROPAGATION_REQUIRED</ prop>
</ props>  
</ property>  
</ bean>  
</ beans>

第二种方式:所有Bean共享一个代理基类

< bean  id ="sessionFactory"  
class ="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
< property  name="configLocation"  value="classpath:hibernate.cfg.xml"  /> 
< property  name="configurationClass"  value="org.hibernate.cfg.AnnotationConfiguration"  />
</ bean> 

<!-- 定义事务管理器(声明式的事务) -->  
< bean  id="transactionManager"
class ="org.springframework.orm.hibernate3.HibernateTransactionManager">
< property  name="sessionFactory"  ref="sessionFactory"  />
</ bean>

< bean  id="transactionBase"  
class ="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" 
lazy-init ="true" abstract ="true">  
<!-- 配置事务管理器 -->  
< property  name="transactionManager"  ref="transactionManager"  />  
<!-- 配置事务属性 -->  
< property  name="transactionAttributes">  
< props>  
< prop  key="*"> PROPAGATION_REQUIRED</ prop>  
</ props>  
</ property>  
</ bean>  

<!-- 配置DAO -->
< bean  id="userDaoTarget"  class="com.bluesky.spring.dao.UserDaoImpl">
< property  name="sessionFactory"  ref="sessionFactory"  />
</ bean>

< bean  id="userDao"  parent="transactionBase"  >  
< property  name="target"  ref="userDaoTarget"  />  
</ bean>
</ beans>

第三种方式:使用拦截器

< bean  id ="sessionFactory"  
class ="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
< property  name="configLocation"  value="classpath:hibernate.cfg.xml"  /> 
< property  name="configurationClass"  value="org.hibernate.cfg.AnnotationConfiguration"  />
</ bean> 

<!-- 定义事务管理器(声明式的事务) -->  
< bean  id="transactionManager"
class ="org.springframework.orm.hibernate3.HibernateTransactionManager">
< property  name="sessionFactory"  ref="sessionFactory"  />
</ bean>  

< bean  id="transactionInterceptor"  
class ="org.springframework.transaction.interceptor.TransactionInterceptor">  
< property  name="transactionManager"  ref="transactionManager"  />  
<!-- 配置事务属性 -->  
< property  name="transactionAttributes">  
< props>  
< prop  key="*"> PROPAGATION_REQUIRED</ prop>  
</ props>  
</ property>  
</ bean>
< bean  class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">  
< property  name="beanNames">  
< list>  
< value> *Dao</ value>
</ list>  
</ property>  
< property  name="interceptorNames">  
< list>  
< value> transactionInterceptor</ value>  
</ list>  
</ property>  
</ bean>  
<!-- 配置DAO -->
< bean  id="userDao"  class="com.bluesky.spring.dao.UserDaoImpl">
< property  name="sessionFactory"  ref="sessionFactory"  />
</ bean>
</ beans>

第四种方式:使用tx标签配置的拦截器

< context:annotation-config  />
< context:component-scan  base-package ="com.bluesky"   />

< bean  id="sessionFactory"  
class ="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
< property  name="configLocation"  value="classpath:hibernate.cfg.xml"  />  
< property  name="configurationClass"  value="org.hibernate.cfg.AnnotationConfiguration"  />
</ bean>  
<!-- 定义事务管理器(声明式的事务) -->  
< bean  id="transactionManager"
class ="org.springframework.orm.hibernate3.HibernateTransactionManager">
< property  name="sessionFactory"  ref="sessionFactory"  />
</ bean>

< tx:advice  id="txAdvice"  transaction-manager="transactionManager">
< tx:attributes>
< tx:method  name="*"  propagation="REQUIRED"  />
</ tx:attributes>
</ tx:advice>

< aop:config>
< aop:pointcut  id="interceptorPointCuts"
expression ="execution(* com.bluesky.spring.dao.*.*(..))"  />
< aop:advisor  advice-ref="txAdvice"
pointcut-ref ="interceptorPointCuts"  />  
</ aop:config>  
</ beans>

第五种方式:全注解

< context:annotation-config  />
< context:component-scan  base-package ="com.bluesky"   />
< tx:annotation-driven  transaction-manager="transactionManager"/>
< bean  id="sessionFactory"  
class ="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
< property  name="configLocation"  value="classpath:hibernate.cfg.xml"  /> 
< property  name="configurationClass"  value="org.hibernate.cfg.AnnotationConfiguration"  />
</ bean> 
<!-- 定义事务管理器(声明式的事务) --> 
< bean  id="transactionManager"
class ="org.springframework.orm.hibernate3.HibernateTransactionManager">
< property  name="sessionFactory"  ref="sessionFactory"  />
</ bean>
</ beans>

此时在DAO上需加上@Transactional注解,如下:

package  com.bluesky.spring.dao;

import  java.util.List;

import  org.hibernate.SessionFactory;
import  org.springframework.beans.factory.annotation.Autowired;
import  org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import  org.springframework.stereotype.Component;

import  com.bluesky.spring.model.User;

@Transactional
@Component( "userDao")
public  class  UserDaoImpl extends  HibernateDaoSupport implements  UserDao {

public  List<User> listUsers() {
return  this .getSession().createQuery("from User").list();
}

}

spring 的singleton 和prototype的区别和应用场合?

singleton作用域:当把一个Bean定义设置为singleton作用域是,Spring IoC容器中只会存在一个共享的Bean实例,并且所有对Bean的请求,只要id与该Bean定义相匹配,则只会返回该Bean的同一实例。值得强调的是singleton作用域是Spring中的缺省作用域。

prototype作用域:prototype作用域的Bean会导致在每次对该Bean请求(将其注入到另一个Bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的Bean实例。对于具有prototype作用域的Bean,有一点很重要,即Spring不能对该Bean的整个生命周期负责。具有prototype作用域的Bean创建后交由调用者负责销毁对象回收资源。

简单的说:

singleton 只有一个实例,也即是单例模式。

prototype访问一次创建一个实例,相当于new。 

应用场合:

1.需要回收重要资源(数据库连接等)的事宜配置为singleton,如果配置为prototype需要应用确保资源正常回收。

2.有状态的Bean配置成singleton会引发未知问题,可以考虑配置为prototype