<?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" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- 如果使用@Transactional方式管理事务,虚做如下声明。
transaction-manager可以省略,前提是有id为transactionManager的Bean
同时,需要在需要用到事务管理方法的上面做如下声明:
@Transactional(propagation=Propagation.REQUIRED, //事务传播
isolation=Isolation.READ_COMMITTED, //事务隔离
rollbackFor=IOException.class, //回滚事务
noRollbackFor=IllegalStateException.class,
timeout=30, //设置超时
readOnly=false) //设置只读属性
-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- Transaction manager for a single hibernate SessionFactory -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!--
事务传播行为(propagation):
REQUIRED 如果有事务在运行,当前的方法就在这个事务内部运行,否则,就启动一个新的事务,并让他在自己的事务内运行
REQUIRED_NEW 当前的方法必须开启新事务,并在他自己的事务中运行,如果有事务在运行,应将他挂起(suspend)
SUPPORTS 如果有事务在运行,当前的方法就运行在这个事务中,否则,他可以不运行在事务中
NOT_SUPPORTED 当前的方法不应该在事务内运行,如果有运行中的事务,就挂起他
MANDATORY 当前的方法必须运行在事务中,如果没有正在运行的事务,就抛出异常
NEVER 当前的方法不应该在事务中运行,如果当前存在事务,就抛出异常
NESTED 如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行。否则,他就启动一个新的事务,并在他自己的事务内部运行
-->
<!--
事务的隔离级别(isolation)
DEFAULT 使用底层数据库的默认隔离级别,对于大多数数据库来说默认隔离级别都是READ_COMMITTED
READ_UMCOMMITTED 允许事务读取未被其他事务提交的变更。脏读、不可重复读和幻读都有可能发生
READ_COMMITTED 只允许事务读取已经被其他事务提交的变更。可以避免脏读问题,但不可重复读和幻读仍可能出现
REPEATABLE——READ 确保事务可以多次从一个字段中读取相同的值。
在这个事务持续期间,禁止其他事务对这个字段进行更新。可以避免脏读和不可重复读,但仍可能出现幻读
SERIALIZABLE 确保事务可以多次从一个表中读取相同的行。
在这个事务执行期间,禁止其他事务对该表执行插入、更新和删除操作。所有并发性问题都可以避免,但是性能十分低下
-->
<!-- 事务通知模式
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*DAO" propagation="REQUIRED" isolation="DEFAULT"
rollback-for="java.io.IOException" no-rollback-for="java.lang.IllegalStateException"
timeout="30" read-only="false" />
<tx:method name="insert" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
-->
<!-- 用事务通知声明式的管理事务 -->
<!--
<aop:config>
<aop:pointcut id="baseService" expression="execution(* org.jhat.dao.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="baseService" order="1"/>
</aop:config>
-->
<!-- Spring AOP 模式
<bean id="userDAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="target" ref="userDAO" />
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="insert">
PROPAGATION_REQUIRED,
ISOLATION_DEFAULT,
-java.io.IOException,+java.lang.IllegalStateException,
timeout_30,readOnly
</prop>
</props>
</property>
</bean>
-->
</beans>
Spring AOP编程,具体的代理类,如果只是需要在被代理的对象执行之前运行,那么只需实现 org.springframework.aop.MethodBeforeAdvice
接口,做相应的处理即可,而 org.springframework.aop.AfterReturningAdvice
和 org.springframework.aop.ThrowsAdvice
则分别用于实现方法调用返回后和抛出异常后的代理接口。当然,还可以通过实现 org.aopalliance.intercept.MethodInterceptor
接口,轻松实现上诉三个功能。但需要注意的是,用代理之后,那么被代理的对象执行完之后返回的结果不在是原有的类型,而变成了被代理对象所实现的接口类,即变成了基类的对象,所以在传参时需要额外注意。同理,若果需要给某个类加上代理,也需要将这个类进行一次抽象,让其实现某一接口。
用Spring AOP做日志记录,给userAction加上日志之后就始终报错
Struts has detected an unhandled exception:
Messages:java.lang.NullPointerException
File:org/apache/struts2/components/UIBean.java
Line number:792
Stacktraces
org.apache.jasper.JasperException: java.lang.NullPointerException
java.lang.NullPointerException
2010-11-24 17:51:54,862 ERROR (com.opensymphony.xwork2.config.providers.InterceptorBuilder:38) - Actual exception
Caught Exception while registering Interceptor class org.jhat.interceptor.BasicInterceptor - interceptor - file:/E:/Program/Tomcat/webapps/jhat/WEB-INF/classes/struts-user.xml:10:86
Caused by: org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type '$Proxy5 implementing org.jhat.service.UserService,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised' to required type 'org.jhat.service.impl.UserServiceImpl' for property 'userService'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [$Proxy5 implementing org.jhat.service.UserService,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [org.jhat.service.impl.UserServiceImpl] for property 'userService': no matching editors or conversion strategy found
Caused by: java.lang.IllegalStateException: Cannot convert value of type [$Proxy5 implementing org.jhat.service.UserService,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [org.jhat.service.impl.UserServiceImpl] for property 'userService': no matching editors or conversion strategy found
大概猜出来是因为类型转换出错,但是给userDAO加上日志却没有报错,而且还能正常记录日志,那么就不应该是类型转换的问题。最后查源代码发现,原来UserAction中的setUserService()方法接受的参数是UserServiceImple类型,我想经过日志代理之后,返回的是向上转型的UserService类型的对象,所以参数类型不一致,最终导致报错,最后将setUserService()方法接受的参数类型改为UserService,再次运行一切正常……
从这一点来看,接口编程模式的确带来了不少好处,实现该接口的类所产生的对象都可以向上转型为接口类型的对象,所以有效地降低了对象之间的耦合度。同时也该注意的是,构造对象时尽量用接口或基类,再用不同的实现类或子类实例化。
今晚去芙蓉餐厅改善伙食,打完饭回来悲剧的发现书包上遗留了某个哥们的菜汤,当时哭的心都有了……
这时候一位阿姨走过来,说:”同学,刚才看见一个同学不小心把菜汤撒你书包上了,我帮你擦一下。“当时那个叫感动啊……然后看个阿姨帮我擦书包,除了说谢谢还是只有说谢谢。本以为,阿姨用抹布擦完就好了,没想到,阿姨又拿出一张餐巾纸,继续擦……再次感动,阿姨是在是太好了。
JDK1.6.0_20 (>1.5)
Apache Tomcat/6.0.26 (>5.x)
MySQL 5.1.51-community (>5.x)
MyEclipse 8.6 for Spring (版本关系不大,版本越高,只是开发越方便)