实施spring AOP事务的方法的漏网之鱼

Spring的事务增强管理,主要是基于各种动态代理或者动态字节码技术; 对于基于接口动态代理的AOP事务来说,因为接口都是要求public的,因此这个问题并不突出; 对于基于CGLIb动态字节码技术的方案来说,因为使用final,static,private修饰的方法不能够被子类覆盖,这些方法都无法进行AOP增强。

因此,在需要事务的场景,一定要注意是否有漏网之鱼。这种隐藏的错误是非常难被发现的。

1) 前提和准备 我们需要利用log4j的debug模式来观察,因此我们需要系统能支持log4j运行; 我们需要观察事务,因此我们要访问一个数据库。

create table FFM_USER( USERNAMEVARCHAR2(64), PASSWORDVARCHAR2(64), LAST_LOGON_TIME VARCHAR2(64), CHARGEINTEGER)

里面有一条数据: 在username字段对应“ffm” 2) 业务场景 UserService里面有很多的方法,有的方法能够被AOP增强,有的不行。 能够被增强的会启动一个事务,如果没有启动事务,,说明无法被AOP增强

3) 实现简单的查看漏网之鱼的源代码 基础父类

package com.spring.special;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * 模拟spring事务嵌套调用的父类 * @author 范芳铭 */ {Logger log = LoggerFactory.getLogger(BaseService.class);}

模拟被spring的AOP事务增强的漏网之鱼

package com.spring.special;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Service;/** * 模拟被spring的AOP事务增强的漏网之鱼 * private, final,static都不能被AOP事务增强,public和protected可以 * @author 范芳铭 */ @Service(“userService”){@Autowired private JdbcTemplate jdbcTemplate;(String userName){updateLastLogonTime(userName);String name = Thread.currentThread().getStackTrace()[1].getMethodName();System.out.println(“当前运行的方法:” + name);}(String userName){updateLastLogonTime(userName);String name = Thread.currentThread().getStackTrace()[1].getMethodName();System.out.println(“当前运行的方法:” + name);}(UserService user){user.updateLastLogonTime(“ffm”);String name = Thread.currentThread().getStackTrace()[1].getMethodName();System.out.println(“当前运行的方法:” + name);}(String userName){updateLastLogonTime(userName);String name = Thread.currentThread().getStackTrace()[1].getMethodName();System.out.println(“当前运行的方法:” + name);}(String userName){updateLastLogonTime(userName);String name = Thread.currentThread().getStackTrace()[1].getMethodName();System.out.println(“当前运行的方法:” + name);}(String userName){String sql = “update ffm_user u set u.last_logon_time = ? where username =? “;jdbcTemplate.update(sql, System.currentTimeMillis(),userName);}(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext(“b_special.xml”);UserService user = (UserService)ctx.getBean(“userService”);user.logon_private(“ffm”);user.logon_final(“ffm”);//静态方法比较特殊,特殊处理下logon_static(user);user.logon_public(“ffm”);user.logon_protected(“ffm”);}}

4)配置文件b_special.xml

====”http://www.springframework.org/schema/task”xsi:schemaLocation=””>== “dataSource” class=”org.apache.commons.dbcp.BasicDataSource”destroy-method = “close”=”${jdbc.o2o.username}”p:password=”${jdbc.o2o.password}” />====>>====>

5)观察和结论 开启DEBUG模式,启动“模拟容器运行”应用。查看日志。 利用“Creating new transaction”在一大堆日志中查找,我们能看到 Creating new transaction with name [com.spring.special.UserService.logon_public]:

Creating new transaction with name [com.spring.special.UserService.logon_protected]:

就只有这两个启动了新的事务。 其他的,就是日志操作方法本身的事务的信息。 Creating new transaction with name [com.spring.special.UserService.updateLastLogonTime]

结论 A被private, final,static修饰的方法都不能被AOP事务增强; B 被public和protected修饰的方法可以被AOP事务增强。 如果在一个方法中,包括了A,也包括了B,那么最终以A为准。

自己不喜欢的人,可以报之以沉默微笑;

实施spring AOP事务的方法的漏网之鱼

相关文章:

你感兴趣的文章:

标签云: