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 如何让企业微信机器人实现消息汇总整合
  • ¥50 关于#ui#的问题:做yolov8的ui界面出现的问题
  • ¥15 如何用Python爬取各高校教师公开的教育和工作经历
  • ¥15 TLE9879QXA40 电机驱动
  • ¥20 对于工程问题的非线性数学模型进行线性化
  • ¥15 Mirare PLUS 进行密钥认证?(详解)
  • ¥15 物体双站RCS和其组成阵列后的双站RCS关系验证
  • ¥20 想用ollama做一个自己的AI数据库
  • ¥15 关于qualoth编辑及缝合服装领子的问题解决方案探寻
  • ¥15 请问怎么才能复现这样的图呀