基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别。(二)

2014-11-24 07:23:37 · 作者: · 浏览: 2
58:44 [main] DEBUG org.springframework.orm.hibernate4.HibernateTransactionManager - Committing Hibernate transaction on Session //提交事务

2012-03-07 09:58:44 [main] DEBUG org.springframework.transaction.support.TransactionSynchronizationManager - Removed value [org.springframework.orm.hibernate4.SessionHolder@1184a4f] for key [org.hibernate.internal.SessionFactoryImpl@107b56e] from thread [main] //解除绑定session到ThreadLocal

到此我们可以看到事务起作用了,也就是说即使把@Transactional放到接口上 基于JDK动态代理也是可以工作的。

三、基于CGLIB类代理:

java代码:

该配置方式是基于CGLIB类代理

启动测试会报错,No Session found for current thread,说明事务没有起作用

java代码:
org.hibernate.HibernateException: No Session found for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1024)
at cn.javass.common.dao.hibernate4.BaseHibernateDao.getSession(BaseHibernateDao.java:63)
at cn.javass.common.dao.hibernate4.BaseHibernateDao.aggregate(BaseHibernateDao.java:238)
at cn.javass.common.dao.hibernate4.BaseHibernateDao.countAll(BaseHibernateDao.java:114)
at cn.javass.common.service.impl.BaseService.countAll(BaseService.java:60)
at cn.javass.common.service.impl.BaseService$$FastClassByCGLIB$$5b04dd69.invoke()
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:618)
at cn.javass.demo.service.impl.UserServiceImpl$$EnhancerByCGLIB$$7d46c567.countAll()
at cn.javass.ssonline.spider.service.impl.UserServiceTest2.testCreate(UserServiceTest2.java:20)

如果将注解放在具体类上或具体类的实现方法上才会起作用。

java代码:
package cn.javass.common.service.impl;
public abstract class BaseService implements IBaseService {

@Transactional() //放在抽象类上
@Override
public int countAll() {
return baseDao.countAll();
}
}

运行测试类,将发现成功了,因为我们的UserService继承该方法,但如果UserService覆盖该方法,如下所示,也将无法织入事务(报错):

java代码:
package cn.javass.demo.service.impl;
public class UserServiceImpl extends BaseService implements UserService {
//没有@Transactional
@Override
public int countAll() {
return baseDao.countAll();
}
}


四、基于aspectj的

java代码:

在此就不演示了,我们主要分析基于JDK动态代理和CGLIB类代理两种的区别。

五、结论:
基于JDK动态代理 ,可以将@Transactional放置在接口和具体类上。

基于CGLIB类代理,只能将@Transactional放置在具体类上。

因此 在实际开发时全部将@Transactional放到具体类上,而不是接口上。

六、分析
1、 JDK动态代理

1.1、Spring使用JdkDynamicAopProxy实现代理:

java代码:
package org.springframework.aop.framework;
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
//注意此处的method 一定是接口上的method(因此放置在接口上的@Transactional是可以发现的)
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
}
}

注意此处的method 一定是接口上的method(因此放置在接口上的@Transactional是可以发现的)

1.2、如果

java代码:
package org.springframework.aop.framework;
final class Cglib2AopProxy implements AopProxy, Serializable {
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
//注意此处的method 一定是具体类上的method(因此只用放置在具体类上的@Transactional是可以发现的)
public Object intercept(Obje