Прокси не может быть передан в класс
Я использую Spring для зависимостей подключений специально для классов DAO, которые используют Hibernate, но я получаю исключение, которое меня озадачивает:
$Proxy58 нельзя отнести к UserDao
Мой DAO настроен следующим образом:
<bean id="userDao" class="com.domain.app.dao.UserDao">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
И у меня есть интерфейс, абстрактный базовый класс и окончательная реализация следующим образом.
Интерфейс:
public interface Dao {
public void save(Object object);
public Object load(long id);
public void delete(Object object);
public void setSessionFactory(SessionFactory sessionFactory);
}
Абстрактный базовый класс:
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();
}
}
Реализация:
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;
}
}
Ниже приведено исключение, указанное выше:
UserDao dao = (UserDao) context.getBean( "userDao" );
Это, однако, не вызывает исключения:
Dao dao = (Dao) context.getBean( "userDao" );
Если кто-либо может предложить какую-либо помощь или руководство относительно того, почему это исключение происходит, я был бы очень благодарен.
Ответы
Ответ 1
Spring по умолчанию использует JDK динамические прокси ($Proxy58
- один из них), который может использовать только прокси-интерфейсы. Это означает, что динамически созданный тип $Proxy58
будет реализовывать один или несколько интерфейсов, реализованных классом wrapped/target (UserDao
), но он не будет фактическим подклассом. Именно поэтому вы можете использовать UserDao
bean для интерфейса Dao
, но не для класса UserDao
.
Вы можете использовать <tx:annotation-driven proxy-target-class="true"/>
, чтобы проинструктировать Spring использовать прокси CGLIB, которые являются фактическими подклассами класса proxied, но я считаю, что лучше использовать программу против интерфейсов. Если вам нужно получить доступ к некоторым методам из прокси-класса, которые не объявлены на одном из интерфейсов, вы должны сначала спросить себя, почему это так?
(Кроме того, в вашем коде выше нет новых методов, введенных в UserDao
, поэтому нет никакого смысла лить bean для этого конкретного типа реализации).
Узнайте больше о различных механизмах проксирования в официальной Spring ссылке.
Ответ 2
Я писал модульные тесты и должен был иметь возможность заглушить DAO для некоторых вызовов.
Per This guys post:
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
}
}
Затем вы можете легко вызвать его с прокси-сервером и получить объект за прокси-сервером и напрямую манипулировать объектами в нем.