spring 代理不能转换为 CLASS

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16047829/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 05:52:35  来源:igfitidea点击:

Proxy cannot be cast to CLASS

springhibernatecasting

提问by mchandler

I'm using Spring for wiring dependencies specifically for DAO classes that use Hibernate, but I'm getting an exception that has me puzzled:

我正在使用 Spring 专门为使用 Hibernate 的 DAO 类连接依赖项,但我遇到了一个让我感到困惑的异常:

$Proxy58 cannot be cast to UserDao

$Proxy58 不能转换为 UserDao

My DAO is configured as follows:

我的DAO配置如下:

<bean id="userDao" class="com.domain.app.dao.UserDao">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

And I have an interface, abstract base class and a final implementation as follows.

我有一个接口、抽象基类和一个最终实现,如下所示。

Interface:

界面:

public interface Dao {
    public void save(Object object);
    public Object load(long id);
    public void delete(Object object);
    public void setSessionFactory(SessionFactory sessionFactory);
}

Abstract Base Class:

抽象基类:

public abstract class BaseDao implements Dao {

    private SessionFactory sessionFactory;

    @Transactional
    @Override
    public void save(Object object) {
        PersistentEntity obj = (PersistentEntity) object;
        currentSession().saveOrUpdate(obj);
    }

    @Transactional
    @Override
    public abstract Object load(long id);

    @Transactional
    @Override
    public void delete(Object object) {
        // TODO: this method!
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public Session currentSession() {
        return sessionFactory.getCurrentSession();
    }

}

Implementation:

执行:

public class UserDao extends BaseDao implements Dao {

    @Transactional(readOnly=true)
    @Override
    public Object load(long id) {
        Object user = currentSession().get(User.class, id);
        return user;
    }

}

The following throws the exception mentioned above:

下面抛出上面提到的异常:

UserDao dao = (UserDao) context.getBean("userDao");

UserDao dao = (UserDao) context.getBean("userDao");

This, however, does not throw an exception:

但是,这不会引发异常:

Dao dao = (Dao) context.getBean("userDao");

Dao dao = (Dao) context.getBean("userDao");

If anyone can offer any assistance or guidance as to why this exception is happening, I would be very appreciative.

如果有人可以就此异常发生的原因提供任何帮助或指导,我将不胜感激。

回答by zagyi

Spring uses JDK dynamic proxiesby default ($Proxy58is one of them), that can only proxy interfaces. This means that the dynamically created type $Proxy58will implement one or more of the interfaces implemented by the wrapped/target class (UserDao), but it won't be an actual subclass of it. That's basically why you can cast the userDaobean to the Daointerface, but not to the UserDaoclass.

Spring默认使用JDK 动态代理$Proxy58是其中之一),只能代理接口。这意味着动态创建的类型$Proxy58将实现一个或多个由包装/目标类 ( UserDao)实现的接口,但它不会是它的实际子类。这基本上就是为什么您可以将userDaobean 转换为Daointerface而不能转换为UserDaoclass 的原因

You can use <tx:annotation-driven proxy-target-class="true"/>to instruct Spring to use CGLIB proxies that are actual subclasses of the proxied class, but I think it's better practice to program against interfaces. If you need to access some methods from the proxied class which are not declared in one of it's interfaces, you should ask yourself first, why this is the case?
(Also, in your code above there are no new methods introduced in UserDao, so there is no point in casting the bean to this concrete implementation type anyway.)

您可以<tx:annotation-driven proxy-target-class="true"/>用来指示 Spring 使用 CGLIB 代理,这些代理是代理类的实际子类,但我认为针对接口进行编程是更好的做法。如果您需要访问代理类中未在其中一个接口中声明的某些方法,您应该先问问自己,为什么会这样?
(此外,在上面的代码中, 中没有引入新方法UserDao,因此无论如何都没有必要将 bean 转换为这个具体的实现类型。)

See more about different proxying mechanisms in the official Spring reference.

在官方Spring 参考中查看有关不同代理机制的更多信息。

回答by Uncle Iroh

I was writing unit tests and needed to be able to stub out the DAOs for some calls. Per This guys post: http://www.techper.net/2009/06/05/how-to-acess-target-object-behind-a-spring-proxy/I used his method provided:

我正在编写单元测试,需要能够为某些调用存根 DAO。每个人发帖:http: //www.techper.net/2009/06/05/how-to-acess-target-object-behind-a-spring-proxy/我使用了他提供的方法:

@SuppressWarnings({"unchecked"})
protected <T> T getTargetObject(Object proxy, Class<T> targetClass) throws Exception {
  if (AopUtils.isJdkDynamicProxy(proxy)) {
    return (T) ((Advised)proxy).getTargetSource().getTarget();
  } else {
    return (T) proxy; // expected to be cglib proxy then, which is simply a specialized class
  }
}

Then you can easily call it with the proxy and get the object behind the proxy and manipulate the objects in it directly as needed.

然后就可以很方便地用代理调用它,获取代理后面的对象,并根据需要直接操作其中的对象。