这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;
}
}
在result = proxy.invokeSuper(obj, args);这个地方调用了未进行代理的dao类的方法;
假设有个BaseHibernateDAO类 里面有这2个方法:
/**
* 取得当期进程的session对象
* @return
*/
public Session getSession() {
return HibernateUtil.getSession();
}
/**
* 保存一个新的实体类的实例,并返回标识号
* @param obj
* @return
*/
public Serializable save(final Object obj) {
return this.getSession().save(obj);
}
注意在save 方法中又调用了getSession()这个方法;
现在来写一个测试类;
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);
}
}
该测试类对BaseHibernateDAO的save方法进行了测试。
这个代码貌似没错,但是在运行的时候抛出了如下错误:
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)
为什么? 经过测试,以及朋友的提醒,发现在BaseHibernateDAO的save()方法里调用了getSession()方法,而在运行的时候CGLIB会对getSession()和save()这2个方法都进行代理,因此在对save()进行tx.commit()和session.flush();的时候,在getSession()方法中已经进行了事务管理并关闭了session。
唉!一不小心就踏入了陷阱。
分享到:
相关推荐
Cglib就是一种实现动态代理的方式,不同于JDK自带的Proxy,Cglib不需要目标对象实现任何接口,因此可以用于不能实现接口的对象。通过Enhancer类,我们可以指定需要代理的目标类,并提供回调方法实现动态代理逻辑。 ...
CGLIB介绍与原理(部分节选自网络) 一、什么是CGLIB?...cglib-nodep-2.2.jar:使用nodep包不需要关联asm的jar包,jar包内部包含asm的类. cglib-2.2.jar:使用此jar包需要关联asm的jar包,否则运行时报错.
1. `cglib-nodep-2.2.jar`:这是CGLIB的主要库,包含了CGLIB的所有功能,但是不依赖于其他的外部库,比如ASM。如果你的项目中已经包含了ASM,或者不需要直接使用ASM,可以选择这个版本。 2. `cglib-2.2.jar`:这个...
- 对于final类和final方法,CGlib无法生成子类进行增强,因为Java不支持final类的子类化。 - 使用CGlib可能会导致内存占用增加,因为它需要创建额外的子类对象。 - 如果目标类的构造函数有参数,使用CGlib时需要...
在Spring中,如果你选择使用基于代理的事务管理,且目标类不实现接口,Spring就会默认使用CGLib来创建代理。通过代理,可以在方法调用前后插入额外的逻辑,如事务控制、性能监控等。 CGLib的使用通常涉及到以下几个...
1. `cglib-nodep-2.1_3.jar`:这是CGLib的核心库,不依赖于任何外部库,包括ASM。它包含了创建代理对象和动态子类所需的所有类和方法。 2. `asm-util-2.2.3.jar`:ASM的工具库,包含了一些实用工具,如类分析器、类...
CGLIB-nodep-2.2.jar是CGLIB的一个无依赖版本,"nodep"即"no dependency"的缩写,意味着这个版本的CGLIB不包含任何外部依赖,只包含了CGLIB自身的核心功能。这对于那些希望减少项目依赖和减小应用体积的开发者来说...
赠送jar包:cglib-3.1.jar; 赠送原API文档:cglib-3.1-javadoc.jar; 赠送源代码:cglib-3.1-sources.jar; 赠送Maven依赖信息文件:cglib-3.1.pom; 包含翻译后的API文档:cglib-3.1-javadoc-API文档-中文(简体)版...
`cglib-nodep-2.2.jar` 是CGLIB的无依赖版本,顾名思义,它不依赖ASM库,而是包含了ASM的必要代码。这个版本的主要目的是解决与其他可能存在的ASM版本冲突的问题。在某些情况下,项目可能已经包含了ASM的一个版本,...
【CGLib:强大的Java代码生成库】 CGLib(Code Generation Library)是一个强大的、高性能的代码生成库,它在运行期扩展Java类与实现Java接口。这个库最初是为EJB的透明代理而设计的,但后来发展成为了一个广泛的...
开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4...
cglib包及依赖汉cglib3.1和asm4.2,主要作用是用户代理,代理为控制要访问的目标对象提供了一种途径。当访问对象时,它引入了一个间接的层。JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理。...
1. CGLIB不能对final类或final方法进行代理,因为无法生成这些类或方法的子类。 2. 代理对象的创建会带来一定的内存和性能开销,因此在不需要代理时,应及时释放代理对象。 总之,CGLIB作为一个强大的字节码生成库...
这个文件是CGlib的主要实现包,不依赖于任何其他的外部库,因此被称为“nodep”(无依赖)。它包含了创建子类并进行方法拦截的核心功能,使得我们可以为一个类创建代理,即使这个类没有实现接口。CGlib通过字节码...
前者是CGLib的核心库,后者是独立版,不依赖于ASM库,适用于那些不希望引入额外依赖的项目。ASM是一个底层的Java字节码操作和分析框架,用于动态生成类和接口的实例。 源码包提供了CGLib的实现细节,包括`cglib-...
Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展. JDK的动态代理有一个限制,就是使用...不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.
总的来说,CGlib是Java开发中不可或缺的工具之一,它提供了强大的代码生成能力,使得开发者可以更加灵活地扩展和增强已有代码,提高代码的复用性和可维护性。这个"cglib所有jar包"资源对于进行Java开发的程序员来说...
CGLib,全称为Code Generation Library,是一个强大的高性能的代码生成库,它在Java世界中被广泛应用,尤其是在动态代理和AOP(面向切面编程)领域。CGLIB是由Evan Schoolnik开发并维护的,它最初是作为Jakarta OGNL...
Cglib是一个强大的Java代码生成库,它在运行时动态创建子类,为现有类提供扩展功能。这个库被广泛用于实现AOP(面向切面编程)中的代理机制,特别是当无法通过接口代理时,例如Java标准库中的类。Cglib是Eclipse的...