添加@Transactional 时无法初始化dao bean
when add @Transactional cannot initialize dao bean
在一个遗留项目的dao中我添加了一个新方法,然后我写了一个单元测试来测试新方法
FooDAO dao = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"}).getBean("FooDAO");
@Test
public void test_getUnenabledArtisanIdsByReverseTime(){
String reverseTimeStr = "2016-02-18 19:00";
List<String> artisanIds = new ArrayList<>();
artisanIds.add("1");
artisanIds.add("2");
dao.getUnenabledArtisanIdsByReverseTime(artisanIds, reverseTimeStr);
}
失败,抛出以下异常
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
然后我在applicationContext.xml
中添加以下配置
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
并在新方法上方添加@Transactional
@Transactional
public List<String> getUnenabledArtisanIdsByReverseTime(List<String> artisanIds, String reverseTimeStr)
然后再次执行单元测试,同样失败,但又是一个异常
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'FooDAO' defined in file [/home/zhuguowei/workspace/myapp/WebContent/WEB-INF/classes/com/foo/artisan/repository/FooDAO.class]:
Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException:
Could not generate CGLIB subclass of class [class com.foo.artisan.repository.FooDAO]:
Common causes of this problem include using a final class or a non-visible class; nested exception is net.sf.cglib.core.CodeGenerationException: java.lang.ClassCastException-->java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527)
很奇怪,道是public而不是最终的class
@Component
public class FooDAO extends BaseDaoHiber4Impl<Foo>
public BaseDaoHiber4Impl() {
this.entryClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
那么这个问题的原因是什么以及如何解决这个问题?
cglib 代理通过创建新的 class、扩展目标 class 并覆盖每个方法来工作。
创建代理时,您的构造函数失败:
(ParameterizedType) getClass().getGenericSuperclass()
getClass() 现在是代理,getGenericSuperclass() 是当前的 class (FooDAO
),不是 ParameterizedType
可能的解决方法:
- 看起来您正在尝试重新实现 spring-data:改为尝试一下:-)
- 不要使用 cglib 代理:为你的 DAO 定义一个接口,让 FooDAO 实现它,然后注入这个接口而不是你的 class。
- 处理扩展 FooDAO 的情况:遍历所有 getGenericSuperclass() 以找到第一个
ParameterizedType
实例
在一个遗留项目的dao中我添加了一个新方法,然后我写了一个单元测试来测试新方法
FooDAO dao = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"}).getBean("FooDAO");
@Test
public void test_getUnenabledArtisanIdsByReverseTime(){
String reverseTimeStr = "2016-02-18 19:00";
List<String> artisanIds = new ArrayList<>();
artisanIds.add("1");
artisanIds.add("2");
dao.getUnenabledArtisanIdsByReverseTime(artisanIds, reverseTimeStr);
}
失败,抛出以下异常
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
然后我在applicationContext.xml
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
并在新方法上方添加@Transactional
@Transactional
public List<String> getUnenabledArtisanIdsByReverseTime(List<String> artisanIds, String reverseTimeStr)
然后再次执行单元测试,同样失败,但又是一个异常
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'FooDAO' defined in file [/home/zhuguowei/workspace/myapp/WebContent/WEB-INF/classes/com/foo/artisan/repository/FooDAO.class]:
Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException:
Could not generate CGLIB subclass of class [class com.foo.artisan.repository.FooDAO]:
Common causes of this problem include using a final class or a non-visible class; nested exception is net.sf.cglib.core.CodeGenerationException: java.lang.ClassCastException-->java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527)
很奇怪,道是public而不是最终的class
@Component
public class FooDAO extends BaseDaoHiber4Impl<Foo>
public BaseDaoHiber4Impl() {
this.entryClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
那么这个问题的原因是什么以及如何解决这个问题?
cglib 代理通过创建新的 class、扩展目标 class 并覆盖每个方法来工作。
创建代理时,您的构造函数失败:
(ParameterizedType) getClass().getGenericSuperclass()
getClass() 现在是代理,getGenericSuperclass() 是当前的 class (FooDAO
),不是 ParameterizedType
可能的解决方法:
- 看起来您正在尝试重新实现 spring-data:改为尝试一下:-)
- 不要使用 cglib 代理:为你的 DAO 定义一个接口,让 FooDAO 实现它,然后注入这个接口而不是你的 class。
- 处理扩展 FooDAO 的情况:遍历所有 getGenericSuperclass() 以找到第一个
ParameterizedType
实例