首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

Spring的事务管理难题剖析(6):特殊方法成漏网之鱼

2012-09-06 
Spring的事务管理难点剖析(6):特殊方法成漏网之鱼哪些方法不能实施Spring AOP事务由于Spring事务管理是基

Spring的事务管理难点剖析(6):特殊方法成漏网之鱼
哪些方法不能实施Spring AOP事务


   由于Spring事务管理是基于接口代理或动态字节码技术,通过AOP实施事务增强的。虽然Spring还支持AspectJ LTW在类加载期实施增强,但这种方法很少使用,所以我们不予关注。
    对于基于接口动态代理的AOP事务增强来说,由于接口的方法都必然是public的,这就要求实现类的实现方法也必须是public的(不能是protected、private等),同时不能使用static的修饰符。所以,可以实施接口动态代理的方法只能是使用“public”或“public final”修饰符的方法,其他方法不可能被动态代理,相应的也就不能实施AOP增强,换句话说,即不能进行Spring事务增强了。
    基于CGLib字节码动态代理的方案是通过扩展被增强类,动态创建其子类的方式进行AOP增强植入的。由于使用final、static、private修饰符的方法都不能被子类覆盖,相应的,这些方法将无法实施AOP增强。所以方法签名必须特别注意这些修饰符的使用,以免使方法不小心成为事务管理的漏网之鱼。

事务增强遗漏实例

   本节中,我们通过具体的实例说明基于CGLib字节码动态代理无法享受Spring AOP事务增强的特殊方法。
  

package com.baobaotao.special;import org.springframework.stereotype.Service;@Service("userService")public class UserService {    //① private方法因访问权限的限制,无法被子类覆盖    private void method1() {        System.out.println("method1");    }    //② final方法无法被子类覆盖    public final void method2() {        System.out.println("method2");    }    //③ static是类级别的方法,无法被子类覆盖    public static void method3() {        System.out.println("method3");    }    //④ public方法可以被子类覆盖,因此可以被动态字节码增强    public void method4() {        System.out.println("method4");    } }


   Spring通过CGLib动态代理技术对UserService Bean实施AOP事务增强的关键配置,具体如下所示:

…    <aop:config proxy-target-advice-ref="jdbcAdvice" order="0"/>    </aop:config>    <tx:advice id="jdbcAdvice" transaction-manager="jdbcManager">        <tx:attributes>            <tx:method name="*"/>        </tx:attributes>    </tx:advice>…


   在①处,我们通过proxy-target-name="code">package com.baobaotao.special;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import org.springframework.stereotype.Service;@Service("userService")public class UserService { … public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("user/special/applicationContext.xml"); UserService service = (UserService) ctx.getBean("userService"); System.out.println("before method1"); service.method1(); System.out.println("after method1"); System.out.println("before method2"); service.method2(); System.out.println("after method2"); System.out.println("before method3"); service.method3(); System.out.println("after method3"); System.out.println("before method4"); service.method4(); System.out.println("after method4"); }}

   在运行UserService之前,将Log4J日志级别设置为DEBUG,运行以上代码查看输出日志,如下所示:

热点排行