linbs28 2008-11-07 21:00
浏览 195
已采纳

CGLIB实现的一个hibernate事务管理代理类出现的问题,以及一些疑问

先声明下,本人系菜鸟一个,问的问题如果类似于1+1为什么等于2,请少拍板

这2天在学习CGLIB,一时兴起用CGLIB实现了一个管理hibernate事务的类。

代码如下:

package com.test;

import java.lang.reflect.Method;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.linbs.core.common.hibernate.HibernateUtil;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**

  • 使用CGLIB进行事务处理设置
  • @author linbs
    */
    public class TransactionDAOProxy implements MethodInterceptor {

    private static Log logger = LogFactory.getLog(TransactionDAOProxy.class);

    private Enhancer enhancer=new Enhancer();

    public Object getDAO(Class clz){
    enhancer.setSuperclass(clz);
    enhancer.setCallback(this);
    return enhancer.create();
    }
    public Object intercept(Object obj, Method method, Object[] args,
    MethodProxy proxy) throws Throwable {
    Session session = null;
    Transaction tx = null;
    Object result = null;

    try{
        session = HibernateUtil.getSession();
        tx = session.beginTransaction();
        result = proxy.invokeSuper(obj, args);
        tx.commit();
        session.flush();
    }catch(HibernateException e){
        try {
            tx.rollback();
        } catch (HibernateException e1) {
            logger.error(e1.getMessage());
            throw e;
        }
    }finally{
        try {
            HibernateUtil.closeSession();
        } catch (HibernateException e) {
            logger.error(e.getMessage());
            throw new Throwable("关闭session时出错!");
        }
    }
    return result;
    

    }

}




其中的HibernateUtil类的getSession()方法是一个从线程中取得session副本的函数,代码相信各位大牛已经很熟悉,在此就不贴出来了。



测试类如下:

package com.test;

import com.linbs.core.common.hibernate.BaseHibernateDAO;
import com.linbs.usermanage.model.User;

public class Test {
public static void main(String[] args){
TransactionDAOProxy proxy = new TransactionDAOProxy();
BaseHibernateDAO baseDAO = (BaseHibernateDAO)proxy.getDAO(BaseHibernateDAO.class);
User user = new User();
user.setUserName("abcProxy");
user.setUserPwd("abcProxy");
user.setEmail("abc@126.cn");
baseDAO.save(user);
}
}





其中的baseDAO.save(user);函数代码如下:

/**
* 取得当期进程的session对象
* @return
*/
public Session getSession() {
return HibernateUtil.getSession();
}
/**
 * 保存一个新的实体类的实例,并返回标识号
 * @param obj
 * @return
 */
public Serializable save(final Object obj) {
    return this.getSession().save(obj);
}







测试类运行的时候报出了如下错误:

Exception in thread "main" org.hibernate.SessionException: Session is closed!

at org.hibernate.impl.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:49)

at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:526)

at org.hibernate.impl.SessionImpl.save(SessionImpl.java:518)

at org.hibernate.impl.SessionImpl.save(SessionImpl.java:514)

at com.linbs.core.common.hibernate.BaseHibernateDAO.save(BaseHibernateDAO.java:31)

at com.linbs.core.common.hibernate.BaseHibernateDAO$$EnhancerByCGLIB$$c88d447e.CGLIB$save$3(<generated>)

at com.linbs.core.common.hibernate.BaseHibernateDAO$$EnhancerByCGLIB$$c88d447e$$FastClassByCGLIB$$e5947bbb.invoke(<generated>)

at net.sf.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:167)

at com.test.TransactionDAOProxy.intercept(TransactionDAOProxy.java:49)

at com.linbs.core.common.hibernate.BaseHibernateDAO$$EnhancerByCGLIB$$c88d447e.save(<generated>)

at com.test.Test.main(Test.java:21)





通过debug发现session = HibernateUtil.getSession();和result = proxy.invokeSuper(obj, args);中调用的session不属于同一个对象。而session是在线程中取得的,可见session = HibernateUtil.getSession();和result = proxy.invokeSuper(obj, args);不是在同一个线程中运行的。于是猜想:cglib在运行中动态创建类而新创建的类和原来创建的类是不在同一线程中运行的,不知道我的猜想是不是正确,请各位大牛指教!!
  • 写回答

1条回答 默认 最新

  • 「已注销」 2008-11-07 22:34
    关注

    [code="java"]enhancer的原理就是用Enhancer生成一个原有类的子类,并且设置好callback到proxy, 则原有类的每个方法调用都会转为调用实现了MethodInterceptor接口的proxy的intercept() 函数:
    public Object intercept(Object o,Method method,Object[] args,MethodProxy proxy)[/code]

    你的代码中代理的是BaseHibernateDAO这个类,再调用save的时候,会内部调用到getSession的方法,而这个方法同样也会给拦截。。同样进入intercept,最后还把事务给提交了,再回到调用真的save的时候,就会出现session已经关闭的提示。。。

    这是我的想法,兄弟你可以再测试测试。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 C++ 头文件/宏冲突问题解决
  • ¥15 用comsol模拟大气湍流通过底部加热(温度不同)的腔体
  • ¥50 安卓adb backup备份子用户应用数据失败
  • ¥20 有人能用聚类分析帮我分析一下文本内容嘛
  • ¥15 请问Lammps做复合材料拉伸模拟,应力应变曲线问题
  • ¥30 python代码,帮调试
  • ¥15 #MATLAB仿真#车辆换道路径规划
  • ¥15 java 操作 elasticsearch 8.1 实现 索引的重建
  • ¥15 数据可视化Python
  • ¥15 要给毕业设计添加扫码登录的功能!!有偿