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();
}
}
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