问题描述
先声明下,本人系菜鸟一个,问的问题如果类似于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在运行中动态创建类而新创建的类和原来创建的类是不在同一线程中运行的,不知道我的猜想是不是正确,请各位大牛指教!!
解决方案
enhancer的原理就是用Enhancer生成一个原有类的子类,并且设置好callback到proxy, 则原有类的每个方法调用都会转为调用实现了MethodInterceptor接口的proxy的intercept() 函数:public Object intercept(Object o,Method method,Object[] args,MethodProxy proxy) 你的代码中代理的是BaseHibernateDAO这个类,再调用save的时候,会内部调用到getSession的方法,而这个方法同样也会给拦截。。同样进入intercept,最后还把事务给提交了,再回到调用真的save的时候,就会出现session已经关闭的提示。。。这是我的想法,兄弟你可以再测试测试。