想在Service 层配置事务,Spring 好象是要求必须用接口,因为我没用接口时没配置成功.
一个IService 接口.声明了所有Service层公共的方法,比如save、delete 等。
public interface IService {
public int count(FindCriteria fc);
public List find(FindCriteria fc);
public Serializable save(Object object) throws UnsupportedOperationException;
}
UserService 接口,声明UserService 的所有方法。还要 extends IService
public interface UserService extends IService {
public User login(User user);
}
UserService接口的实现类.
public class UserServiceImpl implements UserService {
/**
* 登录
*
* @param user
* @return 校验成功的User实例
*/
public User login(User u) throws UnsupportedOperationException {
// throw new UnsupportedOperationException();
User user = (User) userDao.get(User.class, u.getId());
log.debug("get user is " + user);
if (user != null && user.getPassword().equals(u.getPassword()))
return user;
return null;
}
//其他实现省略…
}
完整的applicationContent.xml
<?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-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<!-- 连接属性 -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="WEB-INF/jdbc.properties" />
</bean>
<!-- 数据源 -->
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- hibernate sessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
${hibernate.dialect}
</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.query.substitutions">
true 1, false 0, yes 'Y', no 'N'
</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.batch_size">25</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>cn.xiangyunsoft.busniess.model.Rose</value>
<value>cn.xiangyunsoft.busniess.model.User</value>
<value>cn.xiangyunsoft.busniess.model.Department</value>
</list>
</property>
</bean>
<!-- 配置事务管理 -->
<!-- 事务通知类 -->
<bean id="profiler"
class="cn.xiangyunsoft.busniess.service.SimpleProfiler">
<!-- order 值可以决定通知的先后顺序 ,与后面的order的值的大小,决定了是先通知再执行,还是先执行再通知-->
<property name="order" value="2" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- 以get 、 find 开头的方法是只读事务 -->
<tx:method name="get*" read-only="true" />
<tx:method name="find*" read-only="true" />
<!-- 其他方法是默认 -->
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<aop:config>
<!-- 此处的IService 是表示对所有实现IService接口的类管理事务 -->
<aop:pointcut id="serviceOperation"
expression="execution(* cn.xiangyunsoft.busniess.service.IService.*(..))" />
<aop:advisor advice-ref="txAdvice"
pointcut-ref="serviceOperation" order="1" />
<aop:aspect id="profilingAspect" ref="profiler">
<!-- -->
<aop:pointcut id="serviceMethodWithReturnValue"
expression="execution(!void cn.xiangyunsoft.busniess.service..*Service.*(..))" />
<!-- 通知类型为after-throwing 表示发生异常时通知,还有其他选择 -->
<aop:after-throwing method="profile"
pointcut-ref="serviceMethodWithReturnValue" />
</aop:aspect>
</aop:config>
</beans>
Service 层的bean 在另一个beans.xml文件配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="userService"
class="cn.xiangyunsoft.busniess.service.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
<bean id="userDao"
class="cn.xiangyunsoft.busniess.dao.UserDao">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
</beans>
还有一个执行通知的类
public class SimpleProfiler implements Ordered {
private int order;
// allows us to control the ordering of advice
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
// this method is the around advice
public Object profile(ProceedingJoinPoint call) throws Throwable {
System.out.println("事务执行完成");
Object returnValue;
StopWatch clock = new StopWatch(getClass().getName());
try {
clock.start(call.toShortString());
returnValue = call.proceed();
} finally {
clock.stop();
System.out.println(clock.prettyPrint());
}
return returnValue;
}
}
测试类:
public class BaseServiceTest extends AbstractTransactionalSpringContextTests {
protected String[] getConfigLocations() {
return new String[] { "classpath:/applicationContext_Test.xml",
"beans.xml" };
}
}
public class UserServiceTest extends BaseServiceTest {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public UserService getUserService() {
return userService;
}
@Test
public void testLogin() {
User user = new User("adm");
user.setPassword("admin");
userService.login(user);
}
@Test
public void testSave() {
User user = new User("122");
user.setName("abc");
userService.save(user);
}
}
这两个测试方法一个成功,一个不成功就可以测试出通知发生在不同的时间了。
一点感想:
就是在读Spring手册时不够认真,这个事务配置了好几天,都是不成功,在网上也没有找到合适的解决方法,最后又仔细的读了一次手册,终于成功!教训~!