现在的位置: 首页 > 综合 > 正文

$ProxyXX cannot be cast to 类型

2013年09月22日 ⁄ 综合 ⁄ 共 5375字 ⁄ 字号 评论关闭

今天在做项目的过程中遇到了Spring事务代理类型转换问题($ProxyXX
cannot be cast to 类型),经过网上收集找到了解决方案,特此分享,忘大家多多指教。 
一、问题的来由: (例子基于S2SH框架)
     首先晒晒我的项目包的层次结构:       
--src
-----com.dao.inter 接口包
-----com.dao.base 父类包,实现接口
-----com.dao 子类包,基础父类
-----com.service.inter 接口包
-----com.service.base 父类包,实现接口
-----com.service子类包,基础父类
-----com.service.action父类包,实现接口
-----com.action子类包,基础父类
    在com.dao.inter包中有一个IDAO接口,如下:
public interface IDAO {   
    public List findByHql(String hql);
}
    在com.dao.base包下有一个BaseDao类,该类实现了接口IDAO,如下:     
public class BaseDao extends HibernateDaoSupport implements IDAO {
    public List findByHql(String hql) {
        return this.getHibernateTemplate().find(hql);
    }
}

    在com.dao包下有一个UserDao类,该类继承了父类BaseDao,如下:

public class UserDao extends BaseDao{
    public User loginValidation(String loginName, String loginPassword) {
        return null;
    }
}
    在com.service.inter包下有一个IService接口,如下:
public interface IService {
    public List findByHql(String hql);
}

    在com.service.base包下有一个BaseService类,该类实现了接口IService,如下:

public class BaseService implements IService {
    private IDAO dao;
    public IDAO getDao() {
        return dao;
    }
    public void setDao(IDAO dao) {
        this.dao = dao;
    }
    public List findByHql(String hql) {
         return this.getDao().findByHql(hql);
    }
}

    在com.service包下有一个UserService类,该类继承了父类BaseService,如下:

public class UserService extends BaseService {
    public User loginValidation(String loginName, String loginPassword) {
        return ((UserDao)this.getDao()).loginValidation(loginName, loginPassword);
    }
}

    
com.action包和这个差不多的,不用多说了。在Spring配置文件中实现对象注入,如下:

<!-- 注入sessionFactory到UserDao类 -->
<bean id="userDao" class="com.dao.UserDao">
    <property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- 注入UserDao到UserService类 -->
<bean id="userService" class="com.service.UserService">
    <property name="dao" ref="userDao"></property>
</bean>
<!-- 注入UserService到UserAction类 -->
<bean id="userAction" class="com.action.UserAction">
    <property name="service" ref="userService"></property>
</bean>
    并在Spring中进行了事务配置,如下:
<!-- 配置事务操作 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:advice id="txAdvice" transactionmanager="transactionManager">
    <tx:attributes>
        <tx:method name="add*" propagation="REQUIRED" />
        <tx:method name="insert*" propagation="REQUIRED" />
        <tx:method name="delete*" propagation="REQUIRED" />
        <tx:method name="update*" propagation="REQUIRED" />
        <tx:method name="find*" read-only="false" propagation="SUPPORTS" />
        <tx:method name="select*" read-only="false" propagation="SUPPORTS" />
    </tx:attributes>
</tx:advice>
<aop:config>
    <aop:pointcut id="point" expression="execution(*
com.dao.*.*(..))"
 />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="point" />
</aop:config>
      我在com.action.UserAction(继承了BaseAction类,BaseAction又继承了ActionSupport)实现了Action的操作。在Action处理后调用Service层的业务代理方法,Service层有调用Dao层的数据库操作方法,从而实现一个操作。(这样分层不知是否合理,忘多多指教)
     问题就出在com.service.UserService类中,如下:
java.lang.ClassCastException: $Proxy56 cannot be cast to com.dao.UserDao at comservice.UserService.loginValidation(UserService.java:27) at com.action.UserAction.login(UserAction.java:26)
    于是想为什么会在调用Dao层方法时出错,而不是在调用Service层方法时出错,结合错误(类型转换错误)我做了测试,修改了UserService类的方法,如下:

public User loginValidation(String loginName, String loginPassword) {
    System.out.println(this.getDao());
    System.out.println(this.getDao() instanceof IDAO);
    System.out.println(this.getDao() instanceof BaseDao);
    System.out.println(this.getDao() instanceof UserDao);
    return ((UserDao)this.getDao()).loginValidation(loginName, loginPassword);
}

    输出的结果让我汗颜。如下:

INFO [STDOUT] com.dao.UserDao@1162695
INFO [STDOUT] true
INFO [STDOUT] false
INFO [STDOUT] false
ERROR [[default]] Servlet.service() for servlet default threw exception java.lang.ClassCastException: $Proxy56 cannot be cast to com.dao.UserDao at com.service.UserService.loginValidation(UserService.java:27)
at com.action.UserAction.login(UserAction.java:26)
    this.getDao()对象输入的明明是UserDao类的实例,但是使用instanceof运算符判断输出false,现在还没搞懂为什么(希望知道的告诉我)。按照常理推断,如果是UserDao的实例,后面的都应该输出ture,因为UserDao继承了BaseDao,而BaseDao实现了IDAO,但是该对象只是属于IDAO类型。

二、解决方案
      后来在网上搜了一下,这样的问题很多,但是正真的解决方案并不多。参考http://mopishv0.blog.163.com/blog/static/54455932200911118572079写道
      spring的文档中这么写的:Spring AOP部分使用JDK动态代理或者CGLIB来为目标对象创建代理,如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个CGLIB代理。使用beanNameAutoProxyCreator来进行事务代理的话,他的proxyTargetClass这个属性设置为false(默认是false),即使用JDK动态代理,如果你的service类没有实现接口的话,就会报类型转换错误。
    解决办法有
    1
、给service类添加一个接口iService,让service类实现它,则创建代理类时使用JDK动态代理就不会出现问题
    2、设置beanNameAutoProxyCreatorproxyTargetClass属性为true,意思是强制使用CGLIB代理,前提是你已经将CGLIB包加入到项目中
    推敲了很长时间,因为之前Spring事务用到的并不多,所以不是很了解。
    第一种方法修改UserDao类也实现IDAO接口,但是没有解决。照样报错....
    于是使用了第二种方案,修改了Spring事物配置信息,在原有的配置下加了一句配置如下:
<!-- 配置事务操作 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:advice id="txAdvice" transactionmanager="transactionManager">
    <tx:attributes>
        <tx:method name="add*" propagation="REQUIRED" />
        <tx:method name="insert*" propagation="REQUIRED" />
        <tx:method name="delete*" propagation="REQUIRED" />
        <tx:method name="update*" propagation="REQUIRED" />
        <tx:method name="find*" read-only="false" 

抱歉!评论已关闭.