??xml version="1.0" encoding="utf-8" standalone="yes"?> Spring提供的事务管理可以分Zc:~程式的和声明式的。编E式的,比较灉|Q但是代码量大,存在重复的代码比较多;声明式的比编E式的更灉|方便?/span> Spring提供了几个关于事务处理的c: TransactionDefinition //事务属性定?/span> TranscationStatus //代表了当前的事务Q可以提交,回滚?/span> TransactionTemplate//Spring提供的事务模?/span> PlatformTransactionManagerq个?/span>spring提供的用于管理事务的基础接口Q其下有一个实现的抽象c?/span>AbstractPlatformTransactionManagerQ我们用的事务理cM?/span>DataSourceTransactionManager{都是这个类的子cR?/span> 我们使用~程式的事务理程可能如下Q?/span> (1) 声明数据源?/span> (2) 声明一个事务管理类Q例如:DataSourceTransactionManager,HibernateTransactionManger,JTATransactionManager{?/span> (3) 在我们的代码中加入事务处理代码: TransactionDefinition td = new TransactionDefinition(); TransactionStatus ts = transactionManager.getTransaction(td); try{ //do sth transactionManager.commit(ts); }catch(Exception e){transactionManager.rollback(ts); } 使用Spring提供的事务模?/span>TransactionTemplateQ?/span> void add(){ transactionTemplate.execute( new TransactionCallback(){ public Object doInTransaction(TransactionStatus ts){ //do sth} }} TransactionTemplate也是为我们省M部分事务提交、回滚代?/span>;定义事务模板Ӟ需注入事务理对象?/span> Spring声明式事务处理也主要使用?/span>IoCQ?/span>AOP思想Q提供了TransactionInterceptor拦截器和常用的代理类TransactionProxyFactoryBeanQ可以直接对lgq行事务代理?/span> 使用TransactionInterceptor的步骤: Qbean id = "transactionInterceptor" Q?/span>3Qؓlg声明一个代理类Q?/span>ProxyFactoryBean Qbean id="userManager" class="org.springframework.aop.framework.ProxyFactoryBean"Q?br />
Qproperty name="proxyInterfaces"Q<valueQcom.test.UserManagerQ?valueQ</propertyQ?br />
Qproperty name="interceptorNames"Q?br />
QlistQ?br />
Qidref local="transactionInterceptor"/Q?br />
Q?listQ?br />
Q?propertyQ?br />
Q?beanQ?/span> 使用TransactionProxyFactoryBeanQ?/span> Qbean id="userManager" TransactionProxyFactoryBean只是为组件的事务代理Q如果我们要l组件添加一些业务方面的验证{,可以使用TransactionTemplate加拦截器方式Qؓlgd多个拦截器,spring AOP中提供了三类Advice,卛_增强Q后增强Q抛出异常时的增强,可以灉|使用?/span>
ERROR main org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Instantiation of bean failed; nested exception is java.lang.NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool
Caused by:
java.lang.NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2328)
at java.lang.Class.getConstructor0(Class.java:2640)
at java.lang.Class.getDeclaredConstructor(Class.java:1953)
……
从日志信息看问题已经很明显了Q是applicationContext.xml的dataSource问题?br />
解决ҎQ?br />
1 ?lt;bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
改ؓ<bean id="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource">之后问题得到解决。(org.springframework.jdbc.datasource.DriverManagerDataSource 不可以用连接池。)
2 org.apache.commons.dbcp.BasicDataSource作ؓ注入的DataSource源,Z使用 DBCP的功能,必须要将commons-dbcp.jar加入CLASSPATH中,另外q需要commons-pool.jar和commons- collections.jarQ这些都可以在Spring的lib目录下找到?br />
org.springframework.jdbc.datasource.DriverManagerDataSourceq没有提供连接池的功能,只能作作单的单机q接试。用org.apache.commons.dbcp.BasicDataSource时缺commons-pool.jar所以会出现如题的问题?nbsp;
从日志信息看问题已经很明显了Q是applicationContext.xml的dataSource问题?br />
解决ҎQ?br />
1 ?lt;bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
改ؓ<bean id="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource">之后问题得到解决。(org.springframework.jdbc.datasource.DriverManagerDataSource 不可以用连接池。)
2 org.apache.commons.dbcp.BasicDataSource作ؓ注入的DataSource源,Z使用 DBCP的功能,必须要将commons-dbcp.jar加入CLASSPATH中,另外q需要commons-pool.jar和commons- collections.jarQ这些都可以在Spring的lib目录下找到?br />
org.springframework.jdbc.datasource.DriverManagerDataSourceq没有提供连接池的功能,只能作作单的单机q接试。用org.apache.commons.dbcp.BasicDataSource时缺commons-pool.jar所以会出现如题的问题?
]]> Spring提供的编E式的事务处?/span>
Spring提供的声明式事务处理
Q?/span>1Q定义数据源Q事务管理类
Q?/span>2Q定义事务拦截器,例如Q?/span>
class="org.springframework.transaction.interceptor.TransactionInterceptor"Q?br />
Qproperty name="transactionManager"Q<ref bean="transactionManager"/Q</propertyQ?br />
Qproperty name="transactionAttributeSource"Q?br />
QvalueQ?br />
com.test.UserManager.*r=PROPAGATION_REQUIRED
Q?valueQ?br />
Q?propertyQ?br />
Q?beanQ?/span>
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"Q?br />
Qproperty name="transactionManager"Q<ref bean="transactionManager"/Q</propertyQ?br />
Qproperty name="target"Q<ref local="userManagerTarget"/Q</propertyQ?br />
Qproperty name="transactionAttributes"Q?br />
QpropsQ?br />
Qprop key="insert*"QPROPAGATION_REQUIREDQ?propQ?br />
Qprop key="update*"QPROPAGATION_REQUIREDQ?propQ?br />
Qprop key="*"QPROPAGATION_REQUIRED,readOnlyQ?propQ?br />
Q?propsQ?br />
Q?propertyQ?br />
Q?beanQ?/span>
]]>
Spring 大量引入?/span>Java ?/span>Reflection机制Q通过动态调用的方式避免编码方式的U束Qƈ在此基础上徏立了其核心组?/span>BeanFactoryQ以此作为其依赖注入机制的实现基?/span>
org.springframework.beans包中包括了这些核心组件的实现c,核心中的核心?/span>BeanWrapper?/span>BeanFactorycR(对其源码q行研读Q必有所P?/span>BeanFactory家族如图1所C?/span>
?/span>1 BeanFactory家族
讲的通俗点,是在运行期Q由SpringҎ配置文gQ将其他对象的引用通过lg的提供的setterҎq行讑֮?/span>
通过BeanWrapperQ我们可以无需在编码时指?/span>JavaBean的实现类和属性|通过在配|文件加以设定,可以在q行期动态创建对象ƈ讑֮其属性(依赖关系Q?/span>
Bean FactoryQ顾名思义Q负责创建ƈl护Bean实例?/span>
Bean Factory负责Ҏ配置文g创徏Bean实例Q可以配|的目有:
1Q?/span> Bean属性值及依赖关系Q对其他Bean的引用)
2Q?/span> Bean创徏模式Q是?/span>Singleton模式Q即是否只针Ҏ定类l持全局唯一的实例)
3Q?/span> Bean初始化和销毁方?/span>
4Q?/span> Bean的依赖关p?/span>
联合上面关于BeanWrapper的内容,我们可以看到Q?/span>BeanWrapper实现了针对单?/span>Bean的属性设定操作。?/span>BeanFactory则是针对多个Bean的管理容器,Ҏl定的配|文ӞBeanFactory从中dcd、属性名/|然后通过Reflection机制q行Bean加蝲和属性设定?/span>
ApplicationContext覆盖?/span>BeanFactory的所有功能,q提供了更多的特性。此?/span>ApplicationContextZ现有应用框架相整合,提供了更为开攑ּ的实玎ͼ如对?/span>Web应用Q我们可以在web.xml中对ApplicationContextq行配置Q?/span>
相对BeanFactory而言Q?/span>ApplicationContext提供了以下扩展功能:
1Q?/span> 国际化支持(MessageSourceQ?/span>
我们可以?/span>Beans.xml文g中,对程序中的语a信息Q如提示信息Q进行定义,程序中的提CZ息抽取到配置文g中加以定义,为我们进行应用的各语a版本转换提供了极大的灉|性?/span>
2Q?/span> 资源讉KQ?/span>ResourceLoaderQ?/span>
支持Ҏ件和URL的访问?/span>
3Q?/span> 事g传播Q?/span>ApplicationEventPublisherQ?/span>
事g传播Ҏؓpȝ中状态改变时的检提供了良好支持?/span>
4Q?/span> 多实例加载可以在同一个应用中加蝲多个Context实例。(ListableBeanFactoryQ?/span>
?/span>ApplicationContext的区别:ApplicationContext均通过~码加蝲。对?/span>Web应用Q?/span>Spring提供了可配置?/span>ApplicationContext加蝲机制?/span>
两种加蝲器:ContextLoaderServlet , ContextLoaderListener
配置非常单,?/span>web.xml中增加:
<listener>
<listener-class>org.springframework.web.context.contextLoaderLisenter</listener-class>
</listener>
或:
<servlet>
<servlet-name>context</servlet-name> <servlet-class>org.springframework.web.context.contextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
通过?span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">
用白话来Ԍ是由容器控制程序之间的关系Q而非传统实现中,q序代码直接操控。这也就是所?#8220;控制反{”的概忉|在:控制权由应用代码中{C外部容器Q控制权的{U,是所谓反转?/span>
1.接口注入
2.构造子注入
3.讑ր注?/span>
接口注入模式因ؓ具备侵入性,它要求组件必M特定的接口相兌Q因此ƈ不被看好Q实际用有限?/span>
Type2?/span>Type3的依赖注入实现模式均具备无R入性的特点。在W者看来,q两U实现方式各有特点,也各具优势(一句经典废?/span>JQ?/span>
Type2 构造子注入?span style="border-right: windowtext 1pt solid; padding-right: 0cm; border-top: windowtext 1pt solid; padding-left: 0cm; padding-bottom: 0cm; border-left: windowtext 1pt solid; padding-top: 0cm; border-bottom: windowtext 1pt solid">优势Q?/span>
1Q?/span> “在构造期卛_Z个完整、合法的对象”Q对于这?/span>Java设计原则Q?/span>Type2无疑是最好的
响应者?/span>
2Q?/span> 避免了繁琐的setterҎ的编写,所有依赖关pd在构造函C讑֮Q依赖关p集中呈玎ͼ
更加易读?/span>
3Q?/span> ׃没有setterҎQ依赖关pd构造时由容器一ơ性设定,因此lg在被创徏之后卛_于相?#8220;不变”的稳定状态,无需担心上层代码在调用过E中执行setterҎ对组件依赖关pM生破坏,特别是对?/span>Singleton模式的组件而言Q这可能Ҏ个系l生重大的影响?/span>
4Q?/span> 同样Q由于关联关pM在构造函C表达Q只有组件创需要关心组件内部的依赖关系。对调用者而言Q组件中的依赖关pd于黑盒之中。对上层屏蔽不必要的信息Q也为系l的层次清晰性提供了保证?/span>
5Q?/span> 通过构造子注入Q意味着我们可以在构造函C军_依赖关系的注入顺序,对于一个大量依赖外部服务的lg而言Q依赖关pȝ获得序可能非常重要Q比如某个依赖关pL入的
先决条g是组件的DataSource及相兌源已l被讑֮?/span>
Type3 讑ր注入的优势
1Q?/span> 对于习惯了传l?/span>JavaBean开发的E序员而言Q通过setterҎ讑֮依赖关系昑־更加?/span>
观,更加自然?/span>
2Q?/span> 如果依赖关系Q或l承关系Q较为复杂,那么Type2模式的构造函C会相当庞大(我们需要在构造函C讑֮所有依赖关p)Q此?/span>Type3模式往往更ؓz?/span>
3Q?/span> 对于某些W三方类库而言Q可能要求我们的lg必须提供一个默认的构造函敎ͼ?/span>Struts
中的ActionQ,此时Type2cd的依赖注入机制就体现出其局限性,难以完成我们期望的功
能?br />
注:本文的很多ȝ来源于对《spring框架Q技术详解及使用指导》(作者:夏昕Q的学习?/span>